如何装饰类继承中的最后一个函数
如果我装饰一个超类函数,子类函数将覆盖装饰器。 我想知道是否有一种简洁的方法可以自动装饰MRO中的顶部功能
def wrapper(f):
def _wrap(*args, **kwargs):
print("In wrapper")
return f(*args, **kwargs)
return _wrap
class A:
@wrapper
def f(self):
print("In class A")
class B(A):
def f(self):
print("In class B")
if __name__ == '__main__':
a = A()
b = B()
print("Calling A:")
a.f()
print("Calling B:")
b.f()
这是输出。正如预期的那样,B.f()不调用包装器,尽管我希望它调用
Calling A:
In wrapper
In class A
Calling B:
In class B
以下是我迄今为止所做的尝试。一个元类,它保存所有的装饰器并在类实例化期间注入它们
from abc import ABCMeta
class WrapperMetaClass(ABCMeta):
def __init__(cls, *args, **kwargs):
wrappers_dict = getattr(cls, "_wrappers")
for attr_name in dir(cls):
if attr_name not in wrappers_dict:
continue
else:
wrapper = wrappers_dict[attr_name]
attr = getattr(cls, attr_name)
if not hasattr(attr, '__call__'):
raise Exception("What you're trying to wrap is not a function!")
attr = wrapper(attr)
setattr(cls, attr_name, attr)
super().__init__(*args, **kwargs)
这项工作:
class A(metaclass=WrapperMetaClass):
_wrappers = {
"f": wrapper
}
def f(self):
print("In class A")
class B(A):
def f(self):
print("In class B")
输出就是我想要的
Calling A:
In wrapper
In class A
Calling B:
In wrapper
In class B
然而,这遇到了另一个问题。如果B不重写f,则元类会将A.f()包装两次。这是有意义的,因为A和B都继承WrapperMetaClass,所以A.f()首先被包装,然后B.f()再次被包装
class A(metaclass=WrapperMetaClass):
_wrappers = {
"f": wrapper
}
def f(self):
print("In class A")
class B(A):
pass
输出变为:
Calling A:
In wrapper
In class A
Calling B:
In wrapper
In wrapper
In class A
我不知道我还能做什么
是的,我记得我曾经面对过一两次这样的情况——而你正走在正确的道路上
但首先,如果“包装器”中的逻辑是 可以放在基类中的方法中,然后分解这些方法 在较小的任务中,并有一个“方法槽”系统更可取, 正如user 2357112 supports monica在评论中所说的那样。如果你发现你真的需要或更喜欢装饰,完整的代码如下
因此,经典继承和OO解决了这个问题
如果您需要装饰师安威:
要做的事情是让装饰器本身,即“包装器”,得到 一种“知道”是否已在外部方法(即方法)中调用的方法 在一个调用
super()
)的子类中,只作为一个透明的 在这种情况下,包装当我们需要一个健壮的解决方案时,它会变得更加复杂: 可用于同一类中不同方法的包装器, 如果同时调用它们,则不会感到混淆 (在不同的线程中,或在调用另一个方法的方法中, 不是
super()
,这将触发包装器)最后,其机制非常复杂 它们不应该妨碍你的实际包装-所以, 理想情况下,他们应该作为一个装饰自己,这将 装饰你的包装
[小时后] 因此,如果它看起来不“整洁”,那就很抱歉了——事实证明,实现上面描述的方法比我最初想象的要复杂一些——我们需要一个中间的装饰器级别(在代码中称为
meta_wrapper_applier
),以便元类可以在每次重新声明方法时重新包装它们我希望代码和变量名中的注释足以理解这个想法:
输出:
相关问题 更多 >
编程相关推荐