python - 如何在Python中向继承方法添加装饰器而不复制整个方法?

标签 python inheritance metaprogramming decorator python-decorators

我有一个类从其父类继承修饰属性。我想再添加一个装饰器 (@thedecorator1("yyy")),但不覆盖整个方法和现有的装饰器。 (装饰器的顺序在某种程度上很重要,thedecorator1应该总是在property.setter和thedecorator2之间)

这在 Python 3 中可能吗?

from functools import wraps

class thedecorator1:
    def __init__ (self, idx):
        self.idx = idx
    def __call__ (self, func):
        @wraps(func)
        def wrapped(*args, **kwargs):
            print("thedecorator1", self.idx, args)
            return func(*args, **kwargs)
        return wrapped

def thedecorator2(func):
    def _thedecorator2(self, *args, **kwargs):
        print("thedecorator2",args)
        return func(self, *args, **kwargs)
    return _thedecorator2

class SomeClass:
    """That's te base class"""
    _some_property = None

    @property
    @thedecorator2
    def someproperty(self):
        return self._some_property

    @someproperty.setter
    @thedecorator1("xxx")
    @thedecorator2
    def someproperty(self, value):
        self._some_property = value  

class AnotherClass(SomeClass):
    """That's what works, but I need to copy everything everytime"""

    _some_property = None

    @property
    @thedecorator2
    def someproperty(self):
        return self._some_property

    @someproperty.setter
    @thedecorator1("yyy")
    @thedecorator1("xxx")
    @thedecorator2
    def someproperty(self, value):
        self._someproperty = value

class YetAnotherClass(SomeClass):
    """That's what I think I need"""

    dosomethingsmart(target = someproperty, decorator =  thedecorator1("yyy"), after=someproperty.setter)

最佳答案

没有办法做到这一点,因为装饰器不“知道”在它之前或之后应用的任何其他装饰器。装饰器并不是附加在函数上的额外信息;而是附加在函数上的额外信息。相反,当您使用装饰器时,它会用装饰后的版本替换原始函数。这并不像你有一个包含单个装饰器列表的函数;你只是得到应用所有装饰器的最终结果,压缩成一个对象,并且以后你无法查看内部并知道哪些装饰器正在生效。所以当你写这个时:

class SomeClass:
    """That's te base class"""
    _some_property = None

    @property
    @thedecorator2
    def someproperty(self):
        return self._some_property

现在SomeClass.someproperty是一个属性对象。该属性对象包装了 thedecorator2,但 propertythedecorator2 一无所知;它只是包装其给定的对象。您定义了一个名为 someproperty 的方法,但装饰器将其包装起来并“埋葬”了原始函数;没有通用的方法来“展开”一系列装饰器来访问原始函数或部分装饰的中间函数(例如,应用 thedecorator2 但不是 property)。

后来当你定义AnotherClass时,你说你想“添加一个装饰器”。但为了什么呢?您唯一可以访问的是SomeClass.someproperty。你原来定义的函数不可用;它被“埋”在装饰器下面,你无法将其取出。

现在,对于一些装饰器,您也许能够恢复原始功能。例如,属性将其 getter 函数存储在其 fget 属性中。但是装饰器如何(或者是否!)存储原始函数取决于该装饰器。例如,您的 thedecorator2 装饰器不会以任何方式公开 func。因此,如果AnotherClass确切地知道最初应用了哪些装饰器,它可能能够使用每个装饰器的特定知识来展开它们。但这仍然需要您知道最初应用了哪些装饰器,因此它不会为您节省任何信息,因为不必在 AnotherClass 中复制该信息。

底线是装饰器不会“保存”他们装饰的原始内容;他们只是将其压缩到他们生产的任何产品中。没有通用的方法可以“剥离”已装饰函数的装饰器,甚至无法知道应用了哪些装饰器。因此,你不能有像 insert_new_decorator(somefunction, after=somedecorator) 这样的东西,因为没有办法剥离装饰层来知道 somedecorator 在哪里堆栈。

装饰师不像衣服,你可以脱掉外层夹克,在里面穿上另一件衬衫,然后再穿上原来的夹克。相反,想象一下像草莓一样浸入巧克力中,然后浸入生奶油中,然后淋上糖霜。您无法“打开”奶油和糖霜并在下面涂上不同的巧克力涂层。整个东西融合成一个物体,其各层无法分开。

关于python - 如何在Python中向继承方法添加装饰器而不复制整个方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29980861/

相关文章:

javascript - 如何使此类在 typescript 中可重用?元编程?子类?注入(inject)模块?

c++ - 如何为具有特定类型特征的所有类型编写函数模板?

python - 使用 Python 即时压缩和 ftp 字符串

python - 将扩展与 Selenium (Python) 结合使用

c++ - 这个简单的代码会导致内存泄漏吗?

C++,不能实例化抽象类

python - Scrapy:如何使用正则表达式跟踪页面上的多个链接

python - DRF - 编写双嵌套序列化程序的更好方法

c++ - 合法使用 initializer_list 来初始化具有派生类型的对象吗?

python - 抽象基类中的断言?