实际上,打印声明中的这句话是不正确的:"myfunc有……".第myfunc
号既没有dec1
也没有dec2
.从调用您的修饰符得到的是一个新函数,而不是您传递的函数.我会解释的.
此代码:
@decorator1
@decorator2
def myfunc():
print(f"running myfunc")
相当于:
def myfunc():
print('running myfunc')
myfunc = decorator2(myfunc)
myfunc = decorator1(myfunc)
请记住,您将这些动态属性添加到这wrapped
个函数中.它们并不都适用于相同的myfunc
函数对象.它们适用于"their"包装函数.包装函数是这两个修饰符中的两个不同对象:
myfunc = decorator2(myfunc)
print(myfunc) # <function decorator2.<locals>.wrapped at 0x1028456c0>
myfunc = decorator1(myfunc)
print(myfunc) # <function decorator1.<locals>.wrapped at 0x102845760>
在堆叠装饰物之后,你可以预期decorator1.<locals>.wrapped
个有dec1
个(因为它是外部的),但它没有dec2
个.在decorator2.<locals>.wrapped
号公路上:
def decorator1(f):
def wrapped(*args, **kwargs):
return f(*args, **kwargs)
wrapped.dec1 = True
return wrapped
def decorator2(f):
def wrapped(*args, **kwargs):
return f(*args, **kwargs)
wrapped.dec2 = True
return wrapped
def myfunc():
print('running myfunc')
myfunc = decorator2(myfunc)
myfunc = decorator1(myfunc)
print(f"{getattr(myfunc, 'dec1', False)}") # True
print(f"{getattr(myfunc.__closure__[0].cell_contents, 'dec2', False)}") # True
如果你有这样的装饰师,你的假设就会奏效:
def decorator1(f):
f.dec1 = True
return f
def decorator2(f):
f.dec2 = True
return f
@decorator1
@decorator2
def myfunc():
print('running myfunc')
print(f"{getattr(myfunc, 'dec1', False)}") # True
print(f"{getattr(myfunc, 'dec2', False)}") # True
How can you achieve it with your existing code?
我不认为这是一种干净的方式,但如果你愿意的话,它是有效的:
def decorator1(f):
def wrapped(*args, **kwargs):
return f(*args, **kwargs)
while hasattr(f, '__wrapped__'):
f = f.__wrapped__
f.dec1 = True
wrapped.__wrapped__ = f
return wrapped
def decorator2(f):
def wrapped(*args, **kwargs):
return f(*args, **kwargs)
while hasattr(f, '__wrapped__'):
f = f.__wrapped__
f.dec2 = True
wrapped.__wrapped__ = f
return wrapped
@decorator1
@decorator2
def myfunc():
print('running myfunc')
print(f"{getattr(myfunc.__wrapped__, 'dec1', False)}") # True
print(f"{getattr(myfunc.__wrapped__, 'dec2', False)}") # True
您可以看到,在While循环中,我深入寻找原始的myfunc
并将其添加到返回的包装函数中.另外,我将decX
个属性添加到原来的myfunc
个属性中.