Проблема в том, что когда вы украшаете функцию (или метод) и возвращаете другой объект, вы фактически заменяете функцию (метод) чем-то другим. В вашем случае метод уже не abstractmethod
. Это функция, которая упаковывает abstractmethod
, который не распознается как ABCMeta
.
как абстрактный
Исправление относительно легко в этом случае: functools.wraps
:
import functools # <--- This is new
def logfunc(fn, *args, **kwargs):
@functools.wraps(fn) # <--- This is new
def fncomposite(*args, **kwargs):
rt = fn(*args, **kwargs)
print("Executed %s" % fn.__name__)
return rt
return fncomposite
Это все, что вам нужно изменить.
И с этим изменением на месте оно правильно поднимается:
TypeError: Foo has not implemented abstract methods foo
Однако вам больше не нужно LoggerMeta.__init__
. Вы можете просто позволить ABCMeta
обработать случай, когда есть не реализованные абстрактные методы. Без метода LoggerMeta.__init__
это вызовет еще одно исключение:
TypeError: Can't instantiate abstract class FooImpl with abstract methods foo
functools.wraps
не только правильно обрабатывает абстрактные методы. Он также сохраняет подпись и документацию оформленной функции (и некоторых других приятных вещей). Если вы используете декораторы для простого переноса функций, вы почти всегда хотите использовать functools.wraps
!