我尝试在类级别上运行的with
- 语句方法__enter__
和__exit__
未成功:
class Spam():
@classmethod
def __enter__(cls):
return cls
@classmethod
def __exit__(cls, typ, value, tb):
cls.cleanup_stuff()
with Spam:
pass
但是,这会产生AttributeError
:
Traceback (most recent call last):
File "./test.py", line 15, in <module>
with Spam:
AttributeError: __exit__
是否可以在课堂级别使用__enter__
和__exit__
方法?
答案 0 :(得分:12)
__enter__
和__exit__
是特殊方法,因此仅在defined on a object's type时才能正常工作,而不是在其实例字典中。
现在Spam
是type
的实例,type(Spam).__enter__
和type(Spam).__exit__
不存在。因此,您会收到属性错误。
要使其工作,需要在要使用的类的元类上声明方法。例如:
class Spam(type):
def __enter__(cls):
print('enter')
return cls
def __exit__(cls, typ, value, tb):
print('exit')
class Eggs(metaclass=Spam):
pass
with Eggs:
pass
现在Eggs
是Spam
的实例(type(Eggs)
== Spam
,因此确实存在type(Eggs).__enter__
和type(Eggs).__exit__
。< / p>
然而,定义一个元类只是为了使用它的一个实例作为一个上下文管理器似乎有点过头了。从您的示例开始,更直接的解决方案是使用
with Spam():
pass
或者如果您想稍后重复使用同一个实例:
spam = Spam()
with spam:
pass
答案 1 :(得分:0)
似乎CPython没有调用像instance.__exit__
这样的绑定方法,它会搜索实例类型,执行type(instance).__dict__['__exit__']
之类的操作而不是调用它。由于type(Spam)
是一个特殊的type
对象(不是Spam
本身),因此它不包含__exit__
方法。
我尝试使用元类来解决这个问题,但并没有成功。 __getattr__
也不起作用。
type(self)
type(self).__dict__
(此处没有__getattr__
电话) Python 2的实现方式不同,但关于获取type(self)
的主要想法也适用于它