Конечно, вы можете сделать это динамически. Предположим, у вас есть класс:
>>> class Foo:
... def bar(self): print('bar')
... def baz(self): print('baz')
...
И декоратор:
>>> def deco(f):
... def wrapper(self):
... print('decorated')
... return f(self)
... return wrapper
...
Тогда просто наследуй:
>>> class Foo2(Foo):
... pass
...
Затем переберите исходный класс и примените декоратор к новому дочернему классу:
>>> for name, attr in vars(Foo).items():
... if callable(attr):
... setattr(Foo2, name, deco(attr))
...
Итак ...
>>> x = Foo2()
>>> x.bar()
decorated
bar
>>> x.baz()
decorated
baz
Теперь использование if callable(attr)
может быть недостаточно ограничительным. Возможно, вы захотите игнорировать «более сложные» методы, поэтому вместо этого:
for name, attr in vars(Foo):
if callable(attr) and not name.startswith('__'):
setattr(Foo2, name, attr)
может быть более подходящим. Зависит от вашего варианта использования.
И просто для удовольствия, здесь мы также можем использовать конструктор type
:
In [17]: class Foo:
...: def bar(self): print('bar')
...: def baz(self): print('baz')
...:
In [18]: def deco(f):
...: def wrapper(self):
...: print('decorated')
...: return f(self)
...: return wrapper
...:
In [19]: Foo3 = type(
...: 'Foo3',
...: (Foo,),
...: {name:deco(attr) for name, attr in vars(Foo).items() if callable(attr)}
...: )
In [20]: y = Foo3()
In [21]: y.bar()
decorated
bar
In [22]: y.baz()
decorated
baz