我有两个装饰器。每个装饰器都有一个函数作为参数。每个装饰器都为该函数设置一个属性。在单个函数上链接装饰器后,我希望看到2个新属性。然而,顶部装饰器t2“覆盖”属性t1集。否则,在解决所有问题后t1不再存在。任何人都可以解释为什么以及如何解决它?
def t1(function):
def wrapper(*args, **kwargs):
setattr(wrapper, "t1", True)
return function(*args, **kwargs)
setattr(wrapper, "t1", False)
return wrapper
def t2(function):
def wrapper(*args, **kwargs):
setattr(wrapper, "t2", True)
return function(*args, **kwargs)
setattr(wrapper, "t2", False)
return wrapper
@t2
@t1
def test():
pass
答案 0 :(得分:3)
它发生了,因为你的装饰器在包装器上设置属性。当第一个装饰在其包装器上设置属性时,它将包装器传递给第二个装饰器,在第一个装饰器的顶部添加另一个包装器,并在第二个包装器上设置属性。所以你最终得到了第二个包装器。
In [3]: def decorator_a(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: print("I'm setting the attribute on function {}".format(id(wrapper)))
...: setattr(wrapper, "attr1", True)
...: return wrapper
...:
In [4]: def decorator_b(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: print("I'm setting the attribute on function {}".format(id(wrapper)))
...: setattr(wrapper, "attr2", True)
...: return wrapper
...:
In [5]: first_time_decorated = decorator_a(lambda x: x)
I'm setting the attribute on function 4361847536
In [6]: second_time_decorated = decorator_b(first_time_decorated)
I'm setting the attribute on function 4361441064
您可以通过设置包装器上装饰的函数的所有属性
来解决此问题In [14]: def decorator_a(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: setattr(wrapper, "attr1", True)
...: for attribute in set(dir(fn)) - set(dir(wrapper)):
...: setattr(wrapper, attribute, getattr(fn, attribute))
...: return wrapper
...:
In [15]: def decorator_b(fn):
...: def wrapper(*args, **kwargs):
...: return fn(*args, **kwargs)
...: setattr(wrapper, "attr2", True)
...: for attribute in set(dir(fn)) - set(dir(wrapper)):
...: setattr(wrapper, attribute, getattr(fn, attribute))
...: return wrapper
...:
In [16]: first_time_decorated = decorator_a(lambda x: x)
In [17]: second_time_decorated = decorator_b(first_time_decorated)
In [18]: second_time_decorated.attr1
Out[18]: True
In [19]: second_time_decorated.attr2
Out[19]: True