32

在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

4

5 回答 5

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
于 2019-09-23T11:18:18.977 回答
2

这当然是可能的。用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)

(尚未测试语法,但应该给你的想法)

于 2019-09-17T17:30:21.767 回答
0

我的解决方案是扩展超类的方法而不覆盖它。

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
于 2014-01-18T01:53:10.223 回答
0

Jinksy 的回答对我不起作用,但做了一些小的修改(我使用了不同的名称,但想法应该很清楚):

def my_decorator(func):
    def wrapped(self, x, y):
        print('start')
        result = func(self, x, y)
        print('end')
        return result
    return wrapped
    


class A(ABC):
    @abstractmethod
    def f(self, x, y):
        pass
        
    @my_decorator
    def f_decorated(self, x, y):
        return self.f(x, y)
    

class B(A):
    def f(self, x, y):
        return x + y
    

B().f_decorated(1, 3)
[Out:]
start
end
4   

请注意,这与 Jinksy 所写的重要区别在于抽象方法是 f,并且在调用B().f_decorated它时调用的是继承的非抽象方法。

据我了解,f_decorated可以正确定义,因为abstractmethod装饰器不会干扰装饰器my_decorator

于 2021-05-06T12:53:41.290 回答
0

据我所知,这在 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 术语中,这也不起作用,属性被放置在类本身上,而不是在实例上。换句话说,我想这是可以做到的,但在我看来,它最终会产生令人困惑的代码,而且不像重复几行装饰器那样容易阅读。

于 2019-09-12T15:41:05.990 回答