gpt4 book ai didi

Python:标准函数和上下文管理器?

转载 作者:太空狗 更新时间:2023-10-29 19:28:36 24 4
gpt4 key购买 nike

在 python 中,有许多函数既可以用作标准函数,也可以用作上下文管理器。例如 open() 可以这样调用:

my_file=open(filename,'w')

with open(filename,'w') as my_file:

两者都为您提供一个 my_file 对象,可用于执行您需要的任何操作。一般来说,后者更可取,但有时也可能想做前者。

我已经能够弄清楚如何编写上下文管理器,方法是使用 __enter____exit__ 函数创建一个类,或者使用 @函数上的 contextlib.contextmanager 装饰器和 yield 而不是 return。但是,当我这样做时,我不能再直接使用函数 - 例如,使用装饰器,我得到一个 _GeneratorContextManager 对象而不是想要的结果。当然,如果我把它作为一个类,我只会得到生成器类的一个实例,我认为这本质上是同一件事。

那么我该如何设计一个函数(或类),既可以作为函数返回对象,也可以作为上下文管理器返回 _GeneratorContextManager 等?

编辑:

例如,假设我有一个类似下面的函数(这是高度简化的):

def my_func(arg_1,arg_2):
result=arg_1+arg_2
return my_class(result)

因此该函数接受多个参数,对它们进行处理,并使用这些处理的结果来初始化一个类,然后返回该类。最终结果是我有一个 my_class 的实例,就像我调用 open 时会有一个 file 对象一样。如果我希望能够将这个函数用作上下文管理器,我可以像这样修改它:

@contextlib.contextmanager
def my_func(arg_1,arg_2):
result=arg_1+arg_2 # This is roughly equivalent to the __enter__ function
yield my_class(result)
<do some other stuff here> # This is roughly equivalent to the __exit__function

当作为上下文管理器调用时,它工作得很好,但当作为直接函数调用时,我不再获得 my_class 的实例。也许我只是做错了什么?

编辑 2:

请注意,我可以完全控制 my_class,包括向其添加函数的能力。从下面接受的答案中,我能够推断出我的困难源于一个基本的误解:我在想无论我调用什么(上例中的 my_func)都需要有 __exit____enter__ 函数。这是不正确的。事实上,只有函数返回(上例中的my_class)才需要函数才能作为上下文管理器工作。

最佳答案

您将要遇到的困难是,对于一个既要用作上下文管理器(with foo() as x)又要用作常规函数(x = foo()),从函数返回的对象需要同时具有 __enter____exit__ 方法……而且没有很好的方法——一般来说case — 向现有对象添加方法。

一种方法可能是创建一个包装器类,它使用 __getattr__ 将方法和属性传递给原始对象:

class ContextWrapper(object):
def __init__(self, obj):
self.__obj = obj

def __enter__(self):
return self

def __exit__(self, *exc):
... handle __exit__ ...

def __getattr__(self, attr):
return getattr(self.__obj, attr)

但这会导致一些微妙的问题,因为它与原始函数返回的对象完全不一样(例如,isinstance 测试会失败,一些iter(obj) 之类的内置函数将无法按预期工作,等等)。

您还可以动态地子类化返回的对象,如下所示:https://stackoverflow.com/a/1445289/71522 :

class ObjectWrapper(BaseClass):
def __init__(self, obj):
self.__class__ = type(
obj.__class__.__name__,
(self.__class__, obj.__class__),
{},
)
self.__dict__ = obj.__dict__

def __enter__(self):
return self

def __exit__(self, *exc):
... handle __exit__ ...

但这种方法也有问题(如链接帖子中所述),如果没有强有力的理由,我个人不愿意引入这种魔法。

我通常更喜欢添加显式 __enter____exit__ 方法,或者使用像 contextlib.closing 这样的助手:

with closing(my_func()) as my_obj:
… do stuff …

关于Python:标准函数和上下文管理器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35350897/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com