Украшение класса правильными названиями

Я пытаюсь украсить класс

      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
Другие вопросы по тегам