用正确的名字装饰 class
Decorating a class with the correct names
我正在尝试装饰一个class
def decorate_module(Module):
class Wrapper(Module):
def __init__(self, cfg):
self.c = create_c(**cfg)
super().__init__()
return Wrapper
虽然代码有效,但它给出了一个名为“Wrapper”的 class 而不是原始模块的名称。说到函数修饰,这种情况下可以用@wraps
。我为 class 尝试了同样的事情(通过将其写在 class Wrapper(Module):
上面但出现错误。
正确的做法是什么? python 内置装饰器 @dataclass
似乎可以很好地处理这个问题。我想知道它是如何工作的。有没有像@wraps
这样的辅助函数?还是我应该手动覆盖 __name__
?如果是这样,这种“双下划线”属性的完整列表是什么?
(编辑)我最初的目的
鉴于 class 在 __init__
中不接受任何参数,我想装饰它以接受参数“cfg”,做一些事情(create_c),并且将其存储为属性。
准确地说,我的装饰器实际上将“create_c”作为参数(我在上面的代码中省略了它,因为额外的嵌套会使它变得冗长)。然后,我想按如下方式使用它。
@decorate_module(create_fn1)
class Module1:
...
@decorate_module(create_fn2)
class Module2:
...
对于 class,没有与 functools.wraps
的内置等价物,但您可以自己复制被包装的 class 的双下划线属性,其中包括 __doc__
、__name__
、__qualname__
和 __module__
,如 documented。
def decorate_module(Module):
class Wrapper(Module):
def __init__(self, cfg):
self.c = create_c(**cfg)
super().__init__()
for attr in '__doc__', '__name__', '__qualname__', '__module__':
setattr(Wrapper, attr, getattr(Module, attr))
return Wrapper
据我了解,您需要一种“子类化器”,因此您根本不需要参数 module
(请参阅我的评论)。我使用 __new__
来模拟装饰风格,它会动态创建一个带有 type
内置函数的子类。 __init__
更痛苦:它需要一个额外的函数,因为 __init__
必须总是 return None
class my_dataclass:
def __new__(cls, tcls):
sub_cls = type(f'{tcls.__name__}Jr', (tcls,), {})
def constructor(self, **cfg):
setattr(self, 'c', super(type(self), self).create_c(**cfg))
super(type(self), self).__init__()
setattr(sub_cls, '__init__', lambda self, **cfg: constructor(self, **cfg))
return sub_cls
@my_dataclass
class A:
def __init__(self):
print(self, '__init__')
def create_c(self, **cfg):
print(**cfg)
return 'create_c'
print(A)
a = A()
print(a.c) # attribute
输出
<class '__main__.AJr'>
<__main__.AJr object at 0x7f4105dcc2e0> __init__
create_c
我正在尝试装饰一个class
def decorate_module(Module):
class Wrapper(Module):
def __init__(self, cfg):
self.c = create_c(**cfg)
super().__init__()
return Wrapper
虽然代码有效,但它给出了一个名为“Wrapper”的 class 而不是原始模块的名称。说到函数修饰,这种情况下可以用@wraps
。我为 class 尝试了同样的事情(通过将其写在 class Wrapper(Module):
上面但出现错误。
正确的做法是什么? python 内置装饰器 @dataclass
似乎可以很好地处理这个问题。我想知道它是如何工作的。有没有像@wraps
这样的辅助函数?还是我应该手动覆盖 __name__
?如果是这样,这种“双下划线”属性的完整列表是什么?
(编辑)我最初的目的
鉴于 class 在 __init__
中不接受任何参数,我想装饰它以接受参数“cfg”,做一些事情(create_c),并且将其存储为属性。
准确地说,我的装饰器实际上将“create_c”作为参数(我在上面的代码中省略了它,因为额外的嵌套会使它变得冗长)。然后,我想按如下方式使用它。
@decorate_module(create_fn1)
class Module1:
...
@decorate_module(create_fn2)
class Module2:
...
对于 class,没有与 functools.wraps
的内置等价物,但您可以自己复制被包装的 class 的双下划线属性,其中包括 __doc__
、__name__
、__qualname__
和 __module__
,如 documented。
def decorate_module(Module):
class Wrapper(Module):
def __init__(self, cfg):
self.c = create_c(**cfg)
super().__init__()
for attr in '__doc__', '__name__', '__qualname__', '__module__':
setattr(Wrapper, attr, getattr(Module, attr))
return Wrapper
据我了解,您需要一种“子类化器”,因此您根本不需要参数 module
(请参阅我的评论)。我使用 __new__
来模拟装饰风格,它会动态创建一个带有 type
内置函数的子类。 __init__
更痛苦:它需要一个额外的函数,因为 __init__
必须总是 return None
class my_dataclass:
def __new__(cls, tcls):
sub_cls = type(f'{tcls.__name__}Jr', (tcls,), {})
def constructor(self, **cfg):
setattr(self, 'c', super(type(self), self).create_c(**cfg))
super(type(self), self).__init__()
setattr(sub_cls, '__init__', lambda self, **cfg: constructor(self, **cfg))
return sub_cls
@my_dataclass
class A:
def __init__(self):
print(self, '__init__')
def create_c(self, **cfg):
print(**cfg)
return 'create_c'
print(A)
a = A()
print(a.c) # attribute
输出
<class '__main__.AJr'>
<__main__.AJr object at 0x7f4105dcc2e0> __init__
create_c