使用装饰器链在程序退出时注册类方法
Posted
技术标签:
【中文标题】使用装饰器链在程序退出时注册类方法【英文标题】:Register class method at program exit using chain of decorators 【发布时间】:2019-09-13 22:31:36 【问题描述】:我有一个类,它的一个属性是我想在程序退出时运行的类方法。这个立竿见影的想法:
import atexit
class Foo:
@atexit.register
@classmethod
def foo(cls):
pass
引发以下异常:
Traceback (most recent call last):
File "test.py", line 3, in <module>
class Foo:
File "test.py", line 5, in Foo
@classmethod
TypeError: the first argument must be callable
另一个直接的想法(注意装饰器的评估顺序发生了变化):
import atexit
class Foo:
@classmethod
@atexit.register
def foo(cls):
pass
引发以下异常:
Error in atexit._run_exitfuncs:
TypeError: foo() missing 1 required positional argument: 'cls'
我对装饰器的概念还很陌生。
是否有任何简单的方法可以修复此代码,同时仍使用装饰器链? 如果不是,您会推荐什么作为替代解决方案?【问题讨论】:
【参考方案1】:首先你应该阅读How does a classmethod object work?的答案
但是看看下面代码的输出会很有趣:
def mydeco(func):
print(repr(func))
return func
class Foo:
@mydeco
@classmethod
def foo(cls):
pass
print(repr(Foo.foo))
如果你运行它,你会看到
<classmethod object at 0x6ffffd1dc18>
<bound method Foo.foo of <class '__main__.Foo'>>
所以第一行来自mydeco()
装饰器,第二行来自底部的print()
语句。你会发现它们是不同的。它们不同的原因是因为classmethod
不像您期望的函数装饰器。它不会给你一个函数,而是一个classmethod
对象,它是不可调用的。但是,与此同时,包含它的类Foo
记得在Foo.__dict__
中,当您调用装饰类方法时,它会返回一个可调用方法。
仅仅因为classmethod
对象不可调用。你不能用atexit.register
包装它。 staticmethod
的类似情况。
所以现在您应该意识到,要将其注册到 atexit
,您可以在课堂之外进行,如下所示:
import atexit
class Foo:
@classmethod
def foo(cls):
pass
atexit.register(Foo.foo)
【讨论】:
谢谢!很好解释。 classmethod 对象对我来说有点像黑魔法,但至少我终于明白了“argument is not callable”异常。我不知道装饰器可以返回对象。以上是关于使用装饰器链在程序退出时注册类方法的主要内容,如果未能解决你的问题,请参考以下文章