__enter__ 和 __exit__ 在 python 级别 class 3
__enter__ and __exit__ on class level in python 3
我试图在 class 级别上获得神奇的 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__
是否可以在 class 级别上使用 __enter__
和 __exit__
方法?
似乎 CPython 没有像 instance.__exit__
那样调用绑定方法,它寻找实例类型,做一些像 type(instance).__dict__['__exit__']
的事情而不是调用它。由于 type(Spam)
是一个特殊的 type
对象(不是 Spam
本身),它不包含 __exit__
方法。
我尝试使用元类来解决这个问题,但没有成功。 __getattr__
也不行。
- Py_TYPE 类似于
type(self)
- _PyType_LookupId走过
type(self).__dict__
(这里没有__getattr__
调用)
Python 2 实现不同,但关于获取 type(self)
的主要思想也适用于它
__enter__
和 __exit__
是特殊方法,因此只有在 defined on a object's type 时才能正常工作,而不是在它的实例字典中。
现在Spam
是type
的实例,type(Spam).__enter__
和type(Spam).__exit__
不存在。因此你会得到一个属性错误。
要实现此功能,需要在您要使用的 class 的元 class 上声明这些方法。示例:
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__
确实存在) .
然而定义一个元class只是为了将它的一个实例用作上下文管理器似乎有点过头了。从您的示例开始的更直接的解决方案是仅使用
with Spam():
pass
或者如果您想稍后重用同一个实例:
spam = Spam()
with spam:
pass
我试图在 class 级别上获得神奇的 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__
是否可以在 class 级别上使用 __enter__
和 __exit__
方法?
似乎 CPython 没有像 instance.__exit__
那样调用绑定方法,它寻找实例类型,做一些像 type(instance).__dict__['__exit__']
的事情而不是调用它。由于 type(Spam)
是一个特殊的 type
对象(不是 Spam
本身),它不包含 __exit__
方法。
我尝试使用元类来解决这个问题,但没有成功。 __getattr__
也不行。
- Py_TYPE 类似于
type(self)
- _PyType_LookupId走过
type(self).__dict__
(这里没有__getattr__
调用)
Python 2 实现不同,但关于获取 type(self)
的主要思想也适用于它
__enter__
和 __exit__
是特殊方法,因此只有在 defined on a object's type 时才能正常工作,而不是在它的实例字典中。
现在Spam
是type
的实例,type(Spam).__enter__
和type(Spam).__exit__
不存在。因此你会得到一个属性错误。
要实现此功能,需要在您要使用的 class 的元 class 上声明这些方法。示例:
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__
确实存在) .
然而定义一个元class只是为了将它的一个实例用作上下文管理器似乎有点过头了。从您的示例开始的更直接的解决方案是仅使用
with Spam():
pass
或者如果您想稍后重用同一个实例:
spam = Spam()
with spam:
pass