如何在不复制整个方法的情况下向Python中的继承方法添加装饰器?
我有一个从父类继承装饰属性的类。我想再添加一个decorator(如何在不复制整个方法的情况下向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
@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
类不是从对象继承的,这使它成为一个“旧式类”。许多优秀的类机制在旧式的类(描述符)中不起作用,描述符是编写属性的基础。你的“财产”声明将在那里无效。