Украшение класса правильными названиями
Я пытаюсь украсить класс
def decorate_module(Module):
class Wrapper(Module):
def __init__(self, cfg):
self.c = create_c(**cfg)
super().__init__()
return Wrapper
Пока код работает, он дает класс с именем «Wrapper» вместо имени исходного модуля. Что касается функционального украшения, то в этой ситуации можно использовать. Я попробовал то же самое для класса (написав чуть выше
class Wrapper(Module):
но получил ошибку.
Как правильно это сделать? Встроенный декоратор python
@dataclass
кажется, справляется с этим хорошо. Интересно, как это работает .. Есть ли вспомогательная функция вроде
@wraps
? Или мне следует вручную перезаписать
__name__
? Если да, то каков полный список таких свойств с двойным подчеркиванием?
(РЕДАКТИРОВАТЬ) моя первоначальная цель
Учитывая класс, который не принимает никаких аргументов в
__init__
, Я хотел бы украсить его, чтобы принять аргумент "cfg", сделать что-нибудь (create_c) и сохранить его как атрибут.
Чтобы быть точным, мой декоратор фактически примет «create_c» в качестве аргумента (я пропустил это в приведенном выше коде, поскольку дополнительное вложение сделало бы его подробным). Тогда я думаю использовать его следующим образом.
@decorate_module(create_fn1)
class Module1:
...
@decorate_module(create_fn2)
class Module2:
...
2 ответа
Насколько я понял, вам нужен своего рода «подкласс», поэтому вам вообще не нужен параметр
module
(см. мой комментарий). я использовал
__new__
чтобы имитировать стиль оформления, он динамически создает подкласс с
type
встроенная функция. Более болезненный: он требует дополнительной функции, потому что
__init__
всегда должен возвращаться
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
Нет встроенного эквивалента
functools.wraps
для класса, но вы можете скопировать чертовы атрибуты оборачиваемого класса, которые включают
__doc__
,
__name__
,
__qualname__
а также
__module__
, как в указанодокументации .
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