__在python 3的类级别上输入和退出
我尝试使用-statement方法__在python 3的类级别上输入和退出,python,python-3.x,with-statement,class-method,Python,Python 3.x,With Statement,Class Method,我尝试使用-statement方法\uuuuu enter\uuuuu和\uuuu exit\uuuuu在类级别上运行,但未成功: class Spam(): @classmethod def __enter__(cls): return cls @classmethod def __exit__(cls, typ, value, tb): cls.cleanup_stuff() with Spam: pass 但
\uuuuu enter\uuuuu
和\uuuu exit\uuuuu
在类级别上运行,但未成功:
class Spam():
@classmethod
def __enter__(cls):
return cls
@classmethod
def __exit__(cls, typ, value, tb):
cls.cleanup_stuff()
with Spam:
pass
但是,这将导致属性错误
:
Traceback (most recent call last):
File "./test.py", line 15, in <module>
with Spam:
AttributeError: __exit__
回溯(最近一次呼叫最后一次):
文件“/test.py”,第15行,在
垃圾邮件:
AttributeError:\uuu退出__
是否可以在类级别上使用
\uuuuuuuuuuuuuuu
和\uuuuuuuuuuuuuuuu
方法?似乎CPython不会调用像实例那样的绑定方法。\uuuuuuuuuuuuuuuuuuuuuuuu退出
,它会查找实例类型,执行类似于类型(实例)的操作。而且由于type(Spam)
是一个特殊的type
对象(而不是Spam
本身),因此它不包含\uuuuuuuu退出
方法
我试图用元类解决这个问题,但没有成功<代码>\uuu getattr\uuu
也不起作用
请看这里:
- Py_类型与
类型(自身)
- _PyType\u LookupId遍历
(无类型(self)。\uuuuu dict\uuuuuuu
在此处调用)\uuuuuuu getattr\uuuuuu
Python2实现是不同的,但获取
类型(self)
的主要思想也适用于它\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu和\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
现在,Spam
是type
和type(Spam)的一个实例。\uuuuuuu输入\uuuuuuuuuu和type(Spam)。\uuuuu退出\uuuuuuuuu
不存在。因此,您会得到一个属性错误
为了实现这一点,需要在要使用的类的元类上声明这些方法。例如:
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)。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
然而,定义一个元类只是将其实例用作上下文管理器似乎有点过头了。从您的示例开始,更直接的解决方案是使用
with Spam():
pass
或者,如果以后要重用同一实例:
spam = Spam()
with spam:
pass
我认为@classmethod应该不再需要了。有和没有classmethod时,哪个类将作为cls
传递是有区别的,有了它将是Spam
,没有它将是egs
,所以虽然技术上不需要它,它不一样。+1,但请删除@classmethod
装饰符。元类方法的第一个参数已经是类。用@classmethod
装饰意味着你得到的是元类而不是类,这很少是你想要的。谢谢。这正是我要找的。@Kevin好的,把它删除了,你和@nneonneo是对的,把它放在元类上没有什么意义。这样,cleanup\u stuff
方法也可以在Eggs
上声明,而不仅仅是在Spam
上声明……你为什么还要尝试这样做?我的建议是按预期使用with语句。我打算用类级清理功能扩展peewee.Model类。