python decorator on class: TypeError: super() argument 1 must be type, not function
python decorator on class: TypeError: super() argument 1 must be type, not function
我在 classes 之上使用装饰器来注册组件。这是我的代码
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'>}
但是,在装饰 classes 上调用构造函数会引发错误。
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
我知道装饰后的 class 变成了一个函数,但如何解决这个问题?它只是从文档中不那么明显。
我提到了 PEP-3129 他们说
关于装饰器的详细考察,请参考PEP 318
没有一个 class 带参数装饰器的例子!
我找到的最有用的文档是 Primer on decorators
他们遗漏了 class 个带有参数 的装饰器 。
我研究了 @dataclass
实现并找到了正确的方法。 Unlike what's said in docs and guides elsewhere、Class 装饰器实现与函数装饰器略有不同——我们不需要接收参数并调用它。
这是有效的方法:
def register(cls=None, name=None):
"""
A decorator for registering modules
:param name: (optional) name for this component
"""
def _wrap_cls(cls):
registry[name or cls.__name__] = cls
return cls
if cls is None:
return _wrap_cls
else:
return _wrap_cls(cls)
您面临的问题是,您实际上 return 来自装饰器的函数不再是 class。你为什么不注册 class 然后 return class 本身呢?
registry = {}
def register(name=None):
def inner(cls):
registry[name or cls.__name__] = cls
return cls
return inner
class Base:
def __init__(self, arg):
self.arg = arg
@register(name="file1")
class Module1(Base):
def __init__(self, arg):
super(Module1, self).__init__(arg=arg)
@register()
class Module2(Base):
def __init__(self, arg):
print('init called from Module2')
super(Module2, self).__init__(arg=arg)
print(registry)
print(registry['Module2'](10))
一切正常,输出:
{'file1': <class '__main__.Module1'>, 'Module2': <class '__main__.Module2'>}
init called from Module2
<__main__.Module2 object at 0x000001B83B0B7FD0>
我在 classes 之上使用装饰器来注册组件。这是我的代码
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'>}
但是,在装饰 classes 上调用构造函数会引发错误。
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
我知道装饰后的 class 变成了一个函数,但如何解决这个问题?它只是从文档中不那么明显。
我提到了 PEP-3129 他们说 关于装饰器的详细考察,请参考PEP 318 没有一个 class 带参数装饰器的例子!
我找到的最有用的文档是 Primer on decorators 他们遗漏了 class 个带有参数 的装饰器 。
我研究了 @dataclass
实现并找到了正确的方法。 Unlike what's said in docs and guides elsewhere、Class 装饰器实现与函数装饰器略有不同——我们不需要接收参数并调用它。
这是有效的方法:
def register(cls=None, name=None):
"""
A decorator for registering modules
:param name: (optional) name for this component
"""
def _wrap_cls(cls):
registry[name or cls.__name__] = cls
return cls
if cls is None:
return _wrap_cls
else:
return _wrap_cls(cls)
您面临的问题是,您实际上 return 来自装饰器的函数不再是 class。你为什么不注册 class 然后 return class 本身呢?
registry = {}
def register(name=None):
def inner(cls):
registry[name or cls.__name__] = cls
return cls
return inner
class Base:
def __init__(self, arg):
self.arg = arg
@register(name="file1")
class Module1(Base):
def __init__(self, arg):
super(Module1, self).__init__(arg=arg)
@register()
class Module2(Base):
def __init__(self, arg):
print('init called from Module2')
super(Module2, self).__init__(arg=arg)
print(registry)
print(registry['Module2'](10))
一切正常,输出:
{'file1': <class '__main__.Module1'>, 'Module2': <class '__main__.Module2'>}
init called from Module2
<__main__.Module2 object at 0x000001B83B0B7FD0>