Skip to content

Commit ae11616

Browse files
committed
9.10小节完成~
1 parent b959e94 commit ae11616

File tree

3 files changed

+155
-8
lines changed

3 files changed

+155
-8
lines changed

cookbook/c09/p09_class_decorator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ def __call__(self, *args, **kwargs):
1717
self.ncalls += 1
1818
return self.__wrapped__(*args, **kwargs)
1919

20-
# def __get__(self, instance, cls):
21-
# if instance is None:
22-
# return self
23-
# else:
24-
# return types.MethodType(self, instance)
20+
def __get__(self, instance, cls):
21+
if instance is None:
22+
return self
23+
else:
24+
return types.MethodType(self, instance)
2525

2626
@Profiled
2727
def add(x, y):

cookbook/c09/p10_static_decorator.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python
2+
# -*- encoding: utf-8 -*-
3+
"""
4+
Topic: sample
5+
Desc :
6+
"""
7+
8+
import time
9+
from functools import wraps
10+
11+
# A simple decorator
12+
def timethis(func):
13+
@wraps(func)
14+
def wrapper(*args, **kwargs):
15+
start = time.time()
16+
r = func(*args, **kwargs)
17+
end = time.time()
18+
print(end-start)
19+
return r
20+
return wrapper
21+
22+
# Class illustrating application of the decorator to different kinds of methods
23+
class Spam:
24+
@timethis
25+
def instance_method(self, n):
26+
print(self, n)
27+
while n > 0:
28+
n -= 1
29+
30+
@classmethod
31+
@timethis
32+
def class_method(cls, n):
33+
print(cls, n)
34+
while n > 0:
35+
n -= 1
36+
37+
@staticmethod
38+
@timethis
39+
def static_method(n):
40+
print(n)
41+
while n > 0:
42+
n -= 1
43+
44+
from abc import ABCMeta, abstractmethod
45+
class A(metaclass=ABCMeta):
46+
@classmethod
47+
@abstractmethod
48+
def method(cls):
49+
pass

source/c09/p10_apply_decorators_to_class_and_static_methods.rst

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,112 @@
55
----------
66
问题
77
----------
8-
todo...
8+
你想给类或静态方法提供装饰器。
9+
10+
|
911
1012
----------
1113
解决方案
1214
----------
13-
todo...
15+
给类或静态方法提供装饰器是很简单的,不过要确保装饰器在 ``@classmethod`` 或 ``@staticmethod`` 之前。例如:
16+
17+
.. code-block:: python
18+
19+
import time
20+
from functools import wraps
21+
22+
# A simple decorator
23+
def timethis(func):
24+
@wraps(func)
25+
def wrapper(*args, **kwargs):
26+
start = time.time()
27+
r = func(*args, **kwargs)
28+
end = time.time()
29+
print(end-start)
30+
return r
31+
return wrapper
32+
33+
# Class illustrating application of the decorator to different kinds of methods
34+
class Spam:
35+
@timethis
36+
def instance_method(self, n):
37+
print(self, n)
38+
while n > 0:
39+
n -= 1
40+
41+
@classmethod
42+
@timethis
43+
def class_method(cls, n):
44+
print(cls, n)
45+
while n > 0:
46+
n -= 1
47+
48+
@staticmethod
49+
@timethis
50+
def static_method(n):
51+
print(n)
52+
while n > 0:
53+
n -= 1
54+
55+
装饰后的类和静态方法可正常工作,只不过增加了额外的计时功能:
56+
57+
.. code-block:: python
58+
59+
>>> s = Spam()
60+
>>> s.instance_method(1000000)
61+
<__main__.Spam object at 0x1006a6050> 1000000
62+
0.11817407608032227
63+
>>> Spam.class_method(1000000)
64+
<class '__main__.Spam'> 1000000
65+
0.11334395408630371
66+
>>> Spam.static_method(1000000)
67+
1000000
68+
0.11740279197692871
69+
>>>
70+
71+
|
1472
1573
----------
1674
讨论
1775
----------
18-
todo...
76+
如果你把装饰器的顺序写错了就会出错。例如,假设你像下面这样写:
77+
78+
.. code-block:: python
79+
80+
class Spam:
81+
@timethis
82+
@staticmethod
83+
def static_method(n):
84+
print(n)
85+
while n > 0:
86+
n -= 1
87+
88+
那么你调用这个镜头方法时就会报错:
89+
90+
.. code-block:: python
91+
92+
>>> Spam.static_method(1000000)
93+
Traceback (most recent call last):
94+
File "<stdin>", line 1, in <module>
95+
File "timethis.py", line 6, in wrapper
96+
start = time.time()
97+
TypeError: 'staticmethod' object is not callable
98+
>>>
99+
100+
问题在于 ``@classmethod`` 和 ``@staticmethod`` 实际上并不会创建可直接调用的对象,
101+
而是创建特殊的描述器对象(参考8.9小节)。因此当你试着在其他装饰器中将它们当做函数来使用时就会出错。
102+
确保这种装饰器出现在装饰器链中的第一个位置可以修复这个问题。
103+
104+
当我们在抽象基类中定义类方法和静态方法(参考8.12小节)时,这里讲到的知识就很有用了。
105+
例如,如果你想定义一个抽象类方法,可以使用类似下面的代码:
106+
107+
.. code-block:: python
108+
109+
from abc import ABCMeta, abstractmethod
110+
class A(metaclass=ABCMeta):
111+
@classmethod
112+
@abstractmethod
113+
def method(cls):
114+
pass
115+
116+
在这段代码中,``@classmethod`` 跟 ``@abstractmethod`` 两者的顺序是有讲究的,如果你调换它们的顺序就会出错。

0 commit comments

Comments
 (0)