【发布时间】:2021-08-05 19:11:05
【问题描述】:
我在类之上使用装饰器来注册组件。这是我的代码
import functools
registry = {}
def register(name=None):
"""A decorator for registering modules
:param name: (optional) name for component
"""
def _wrap_func(func):
registry[name or func.__name__] = func
@functools.wraps(func)
def _wrap_args(*args, **kwargs):
return func(*args, **kwargs)
return _wrap_args
return _wrap_func
class Base:
def __init__(self, arg):
self.arg = arg
@register(name="module1")
class Module1(Base):
def __init__(self, arg):
super(Module1, self).__init__(arg=arg)
# super().__init__(arg=arg)
@register(name="module2")
class Module2(Base):
def __init__(self, arg):
super(Module2, self).__init__(arg=arg)
到目前为止还不错。 registry 和 register 按预期工作
print(registry)
# {'module1': <class '__main__.Module1'>, 'module2': <class '__main__.Module2'>}
但是,在装饰类上调用构造函数会引发错误。
module1 = Module1(arg='some1')
print(module1)
Traceback (most recent call last):
File "/tmp.py", line xx, in <module>
module1 = Module1(arg='some1')
File "/tmp.py", line xx, in _wrap_args
return func(*args, **kwargs)
File "/tmp.py", line xx, in __init__
super(Module1, self).__init__(arg=arg)
TypeError: super() argument 1 must be type, not function
我以为functools.wraps 负责隐藏装饰器,但这里不是。
如果我将super(Module1, self).__init__(arg=arg) 更改为super().__init__(arg=arg),它可以工作!
这是装饰器的预期行为还是我对 registry() 函数的定义有问题?
编辑:我最近发现继承被破坏了
@register(name="module3")
class Module3(Module1):
pass
导致
Traceback (most recent call last):
File "tmp.py", line xx, in <module>
class Module3(Module1):
TypeError: function() argument 'code' must be code, not str
我知道装饰类变成了一个函数,但是如何解决这个问题?它只是从文档中不那么明显。
-
我发现的最有用的文档是Primer on decorators 他们省略了类装饰器带参数。
【问题讨论】:
-
可能是因为类不是函数?
-
这是否意味着我们不应该在(派生)类上使用装饰器?
-
atm 的问题是,一旦装饰,
Module1就被视为一个函数,(即来自装饰器的_wrap_func()。所以尽可能使用super().。跨度> -
register被编写为函数装饰器。你为什么把它应用到课堂上?或者如果它应该是一个类装饰器,为什么它返回函数?
标签: python python-3.x python-decorators