9.3 解除一个装饰器¶
问题¶
一个装饰器已ç»�ä½œç”¨åœ¨ä¸€ä¸ªå‡½æ•°ä¸Šï¼Œä½ æƒ³æ’¤é”€å®ƒï¼Œç›´æŽ¥è®¿é—®åŽŸå§‹çš„æœªåŒ…è£…çš„é‚£ä¸ªå‡½æ•°ã€‚
解决方案¶
å�‡è®¾è£…饰器是通过 @wraps (å�‚考9.2å°�节)æ�¥å®žçŽ°çš„ï¼Œé‚£ä¹ˆä½ å�¯ä»¥é€šè¿‡è®¿é—® __wrapped__ 属性æ�¥è®¿é—®åŽŸå§‹å‡½æ•°ï¼š
>>> @somedecorator
>>> def add(x, y):
... return x + y
...
>>> orig_add = add.__wrapped__
>>> orig_add(3, 4)
7
>>>
讨论¶
直接访问未包装的原始函数在调试�内�和其他函数�作时是很有用的。
ä½†æ˜¯æˆ‘ä»¬è¿™é‡Œçš„æ–¹æ¡ˆä»…ä»…é€‚ç”¨äºŽåœ¨åŒ…è£…å™¨ä¸æ£ç¡®ä½¿ç”¨äº† @wraps 或者直接设置了 __wrapped__ 属性的情况。
如果有多个包装器,那么访问 __wrapped__ 属性的行为是ä¸�å�¯é¢„知的,应该é�¿å…�è¿™æ ·å�šã€‚
在Python3.3ä¸ï¼Œå®ƒä¼šç•¥è¿‡æ‰€æœ‰çš„包装层,比如,å�‡å¦‚ä½ æœ‰å¦‚ä¸‹çš„ä»£ç �:
from functools import wraps
def decorator1(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('Decorator 1')
return func(*args, **kwargs)
return wrapper
def decorator2(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('Decorator 2')
return func(*args, **kwargs)
return wrapper
@decorator1
@decorator2
def add(x, y):
return x + y
下�我们在Python3.3下测试:
>>> add(2, 3)
Decorator 1
Decorator 2
5
>>> add.__wrapped__(2, 3)
5
>>>
下�我们在Python3.4下测试:
>>> add(2, 3)
Decorator 1
Decorator 2
5
>>> add.__wrapped__(2, 3)
Decorator 2
5
>>>
最å�Žè¦�说的是,并ä¸�是所有的装饰器都使用了 @wraps ï¼Œå› æ¤è¿™é‡Œçš„æ–¹æ¡ˆå¹¶ä¸�全部适用。
特别的,内置的装饰器 @staticmethod 和 @classmethod 就没有�循这个约定
(它们把原始函数å˜å‚¨åœ¨å±žæ€§ __func__ ä¸)。