Python链接修饰符覆盖属性

2024-04-27 05:04:07 发布

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

我有两个装修工。每个decorator都得到一个函数作为参数。每个decorator为函数设置一个属性。在将装饰器链接到单个函数之后,我希望看到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

Tags: 函数falsetruereturn属性defargsfunction
1条回答
网友
1楼 · 发布于 2024-04-27 05:04:07

这种情况会发生,因为您的装饰器在包装器上设置了属性。当第一个decorated在其包装上设置属性时,它将包装传递给第二个decorater,后者在第一个包装上添加另一个包装并在第二个包装上设置属性。所以你最后得到了第二个包装。你知道吗

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

相关问题 更多 >