Skip to content

Commit d1f6732

Browse files
committed
9.3小节完成~
1 parent ade2f5d commit d1f6732

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

cookbook/c09/p03_unwrap_decorator.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
"""
4+
Topic: 解除包装器
5+
Desc :
6+
"""
7+
8+
from functools import wraps
9+
10+
def decorator1(func):
11+
@wraps(func)
12+
def wrapper(*args, **kwargs):
13+
print('Decorator 1')
14+
return func(*args, **kwargs)
15+
return wrapper
16+
17+
def decorator2(func):
18+
@wraps(func)
19+
def wrapper(*args, **kwargs):
20+
print('Decorator 2')
21+
return func(*args, **kwargs)
22+
return wrapper
23+
24+
@decorator1
25+
@decorator2
26+
def add(x, y):
27+
return x + y
28+
29+
add(1, 2)
30+
print('-----------------')
31+
print(add.__wrapped__(2, 3))

source/c09/p03_unwrapping_decorator.rst

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,85 @@
55
----------
66
问题
77
----------
8-
todo...
8+
一个装饰器已经作用在一个函数上,你想撤销它,直接访问原始的未包装的那个函数。
9+
10+
|
911
1012
----------
1113
解决方案
1214
----------
13-
todo...
15+
假设装饰器是通过 ``@wraps`` (参考9.2小节)来实现的,那么你可以通过访问 ``__wrapped__`` 属性来访问原始函数:
16+
17+
.. code-block:: python
18+
19+
>>> @somedecorator
20+
>>> def add(x, y):
21+
... return x + y
22+
...
23+
>>> orig_add = add.__wrapped__
24+
>>> orig_add(3, 4)
25+
7
26+
>>>
27+
28+
|
1429
1530
----------
1631
讨论
1732
----------
18-
todo...
33+
直接访问未包装的原始函数在调试、内省和其他函数操作时是很有用的。
34+
但是我们这里的方案仅仅适用于在包装器中正确使用了 ``@wraps`` 或者直接设置了 ``__wrapped__`` 属性的情况。
35+
36+
如果有多个包装器,那么访问 ``__wrapped__`` 属性的行为是不可预知的,应该避免这样做。
37+
在Python3.3中,它会略过所有的包装层,比如,假如你有如下的代码:
38+
39+
.. code-block:: python
40+
41+
from functools import wraps
42+
43+
def decorator1(func):
44+
@wraps(func)
45+
def wrapper(*args, **kwargs):
46+
print('Decorator 1')
47+
return func(*args, **kwargs)
48+
return wrapper
49+
50+
def decorator2(func):
51+
@wraps(func)
52+
def wrapper(*args, **kwargs):
53+
print('Decorator 2')
54+
return func(*args, **kwargs)
55+
return wrapper
56+
57+
@decorator1
58+
@decorator2
59+
def add(x, y):
60+
return x + y
61+
62+
下面我们在Python3.3下测试:
63+
64+
.. code-block:: python
65+
66+
>>> add(2, 3)
67+
Decorator 1
68+
Decorator 2
69+
5
70+
>>> add.__wrapped__(2, 3)
71+
5
72+
>>>
73+
74+
下面我们在Python3.4下测试:
75+
76+
.. code-block:: python
77+
78+
>>> add(2, 3)
79+
Decorator 1
80+
Decorator 2
81+
5
82+
>>> add.__wrapped__(2, 3)
83+
Decorator 2
84+
5
85+
>>>
86+
87+
最后要说的是,并不是所有的装饰器都使用了 ``@wraps`` ,因此这里的方案并不全部适用。
88+
特别的,内置的装饰器 ``@staticmethod`` 和 ``@classmethod`` 就没有遵循这个约定
89+
(它们把原始函数存储在属性 ``__func__`` 中)。

0 commit comments

Comments
 (0)