如何在Python中为继承的方法添加一个decorator而不复制整个方法?

2024-05-14 02:54:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个类从其父类继承装饰属性。我想再添加一个decorator(@thedecorator1("yyy")),但不重写整个方法和现有的decorator。(装饰工的顺序在某种程度上很重要,装饰工1应始终介于属性.setter以及Decorator2)

在Python3中这是可能的吗?在

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)

Tags: selfreturnvaluedefargspropertysomekwargs
2条回答

没有办法做到这一点,因为一个装饰者并不“知道”在它之前或之后应用的任何其他装饰器。decorator不是附加到函数的额外信息;相反,当您使用decorator时,它会用修饰后的版本替换原来的函数。它不像你有一个单独的装饰器列表的函数;你只是得到了应用所有装饰器的最终结果,压缩到一个对象中,然后你就不能窥视内部并知道哪些装饰器在起作用。所以当你写这篇文章时:

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

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

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

稍后当您定义另一个类时,您会说您想要“添加一个装饰器”。但是为了什么?您唯一可以访问的是SomeClass.someproperty。您定义的原始函数不可用;它被“隐藏”在decorators之下,您无法将其取出。在

现在,对于一些修饰符,您可能可以恢复原来的函数。例如,property将其getter函数存储在其fget属性中。但如何(或如果!)一个decorator存储原始函数是由那个decorator决定的。例如,thedecorator2修饰符不会以任何方式公开func。如果每个人都知道哪些装饰物是可以使用的。但这仍然要求您知道最初应用了哪些修饰符,因此它不会为您节省任何不必在AnotherClass中复制该信息的情况。在

归根结底,装潢师不会“保存”他们所装饰的最初的东西;他们只是将其压缩成他们生产的任何东西。没有通用的方法来“剥离”已装饰函数的装饰器,甚至不知道应用了哪些装饰器。因此,您不能有类似insert_new_decorator(somefunction, after=somedecorator)的内容,因为没有办法从装饰层中剥离出来来知道somedecorator在堆栈中的位置。在

装饰家不像衣服,你可以脱下外套,在里面换上不同的衬衫,然后再穿上原来的夹克。更确切地说,想象一下草莓蘸上巧克力,然后蘸上鲜奶油,再淋上糖霜。你不能“拆开”奶油和糖霜,在下面涂上不同的巧克力涂层。整个物体被融合成一个物体,而这个物体的层是不能被分开的。在

考虑一下这个程序:

from functools import wraps

def dec1(fn):
    @wraps(fn)
    def wrap(*args, **kw):
        print "dec1", fn.__name__
        return fn(*args, **kw)
    return wrap

def dec2(fn):
    @wraps(fn)
    def wrap(*args, **kw):
        print "dec2", fn.__name__
        return fn(*args, **kw)
    return wrap

class C(object):
    prop = None
    @property
    def foo(self):
        return self.prop

    @foo.setter
    @dec1
    def foo(self, x):
        self.prop = x

class D(C):
    foo = property(
        C.foo.fget,
        dec2(C.foo.fset),
        C.foo.fdel)

print '.'
c=C()
c.foo = 7
print '.'
d = D()
d.foo = 8
print '.'

foo是从C.foo继承get和delete函数的属性,但包装了set函数。在

D的另一个定义是:

^{pr2}$

无论哪种情况,程序的输出都是:

.
dec1 foo
.
dec2 foo
dec1 foo
.

注意,c.foo的赋值调用一个包装器,而对d.foo的赋值同时调用这两个包装器。在

相关问题 更多 >