Декораторы по абстрактным методам
В python существует ли способ сделать декоратор абстрактного метода переносимым на производную реализацию (ы)?
Например, в
import abc
class Foo(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
@some_decorator
def my_method(self, x):
pass
class SubFoo(Foo):
def my_method(self, x):
print x
Насколько я могу сказать,
SubFoo
my_method
не будет украшен some_decorator
. Есть ли способ сделать это без индивидуального украшения каждого производного класса Foo
?
Ответы
Ответ 1
Это, конечно, возможно. В Python мало что нельзя сделать, ха-ха! Я оставлю ли вам хорошую идею...
class MyClass:
def myfunc():
raise NotImplemented()
def __getattribute__(self, name):
if name == "myfunc":
func = getattr(type(self), "myfunc")
return mydecorator(func)
return object.__getattribute__(self, name)
(еще не проверен на синтаксис, но должен дать вам представление)
Ответ 2
Мое решение будет расширять метод суперкласса без его переопределения.
import abc
class Foo(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
@some_decorator
def my_method(self, x):
pass
class SubFoo(Foo):
def my_method(self, x):
super().my_method(x) #delegating the call to the superclass
print x
Ответ 3
Насколько я знаю, это не возможно и не очень хорошая стратегия в Python. Здесь больше объяснений.
Согласно документации abc:
Когда abstractmethod() применяется в сочетании с другими дескрипторами метода, его следует применять как самый внутренний декоратор, как показано в следующих примерах использования:...
Другими словами, мы могли бы написать ваш класс следующим образом (стиль Python 3):
from abc import ABCMeta, abstractmethod
class AbstractClass(metclass=ABCMeta):
@property
@abstactmethod
def info(self):
pass
Но тогда что? Если вы унаследованы от AbstractClass
и попытаетесь переопределить свойство info
без указания декоратора @property
, это может привести к путанице. Помните, что для краткости свойства (и это только пример) обычно используют одно и то же имя для метода класса:
class Concrete(AbstractMethod):
@property
def info(self):
return
@info.setter
def info(self, new_info):
new_info
В этом контексте, если вы не будете повторять декораторы @property
и @info.setter
, это может привести к путанице. В терминах Python это тоже не сработает, свойства помещаются в сам класс, а не в экземпляр. Другими словами, я полагаю, что это можно было бы сделать, но, в конце концов, это создало бы запутанный код, который, по моему мнению, не так легко читать, как повторение нескольких строк декоратора.
Ответ 4
Я бы закодировал его как два разных метода, как в стандартном описании фабричного метода.
https://www.oodesign.com/factory-method-pattern.html
class Foo(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
@some_decorator
def my_method(self, x):
self.child_method()
class SubFoo(Foo):
def child_method(self, x):
print x