Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在不复制整个方法的情况下向Python中的继承方法添加装饰器?_Python_Inheritance_Metaprogramming_Decorator_Python Decorators - Fatal编程技术网

如何在不复制整个方法的情况下向Python中的继承方法添加装饰器?

如何在不复制整个方法的情况下向Python中的继承方法添加装饰器?,python,inheritance,metaprogramming,decorator,python-decorators,Python,Inheritance,Metaprogramming,Decorator,Python Decorators,我有一个从父类继承装饰属性的类。我想再添加一个decorator(@thedecorator1(“yyy”)),但不覆盖整个方法和现有的decorator。(装饰者的顺序在某种程度上很重要,装饰者1应始终介于property.setter和装饰者2之间) 这在Python3中可能吗 from functools import wraps class thedecorator1: def __init__ (self, idx): self.idx = idx d

我有一个从父类继承装饰属性的类。我想再添加一个decorator(
@thedecorator1(“yyy”)
),但不覆盖整个方法和现有的decorator。(装饰者的顺序在某种程度上很重要,装饰者1应始终介于property.setter和装饰者2之间)

这在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)
考虑一下这个计划:

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 '.'
D.foo是从C.foo继承get和delete函数的属性,但包装set函数

D
的另一个定义是:

class D(C):
    foo = C.foo.setter(dec2(C.foo.fset))
无论哪种情况,程序的输出都是:

。
十二月一日
.
十二月二日
十二月一日
.

请注意,对
c.foo
的分配调用一个包装,而对
d.foo
的分配调用两个包装。

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

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

    @property
    @thedecorator2
    def someproperty(self):
        return self._some_property
现在
SomeClass.someproperty
是一个属性对象。该属性对象包装了Decorator2,但
属性
对Decorator2一无所知;它只是将给定的对象包装起来。您定义了一个名为
someproperty
的方法,但装饰程序将其包装并“掩埋”原始函数;没有通用的方法“解开”一系列修饰符以访问原始函数或部分修饰的中间函数(例如,应用
修饰符2
而不是
属性的结果)

稍后当您定义另一个类时,您会说您想要“添加一个装饰器”。但是为了什么?您唯一可以访问的是
SomeClass.someproperty
。您定义的原始函数不可用;它被“掩埋”在装修工的下面,你无法把它拿出来

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

底线是,装饰者不会“保存”他们装饰的原始物品;他们只是把它压成他们生产的任何东西。没有通用的方法可以“剥离”已修饰函数的装饰器,甚至无法知道应用了哪些装饰器。因此,您不能使用类似于插入新的装饰器(somefunction,after=somedecorator)
的东西,因为无法返回到装饰层以了解
somedecorator
在堆栈中的位置


装潢师不像衣服,你可以脱下外套,在里面穿上不同的衬衫,然后再穿上原来的夹克。相反,想象一下草莓蘸巧克力,然后蘸鲜奶油,然后撒上糖霜。你不能“打开”奶油和糖霜,在下面涂上不同的巧克力涂层。整个东西被融合到一个对象中,其层无法分离。

回答很好——也许你可以添加一段,说明如果子类中添加的装饰器总是最外层的(当然,这排除了已经是
属性的方法),那么它是可行的,需要做的就是不要使用decorator语法,而是在类主体上写一些东西:
some\u祖先\u方法=newdecorator(SomeClass.\u dict\u[“some\u祖先\u方法])
请,请注意,这是有效的Python3,但在Python2.x中不起作用,因为您的
Decorator1
类不是从对象继承的,这使它成为一个“旧式类”。许多优秀的类机制在旧式的类(描述符)中不起作用,描述符是编写属性的基础。你的“财产”声明将在那里无效。