Декораторы по абстрактным методам

В 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