9.10 为类和��方法�供装饰器¶
问题¶
ä½ æƒ³ç»™ç±»æˆ–é�™æ€�方法æ��供装饰器。
解决方案¶
给类或��方法�供装饰器是很简�的,�过�确�装饰器在 @classmethod 或 @staticmethod 之�。例如:
import time
from functools import wraps
# A simple decorator
def timethis(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
r = func(*args, **kwargs)
end = time.time()
print(end-start)
return r
return wrapper
# Class illustrating application of the decorator to different kinds of methods
class Spam:
@timethis
def instance_method(self, n):
print(self, n)
while n > 0:
n -= 1
@classmethod
@timethis
def class_method(cls, n):
print(cls, n)
while n > 0:
n -= 1
@staticmethod
@timethis
def static_method(n):
print(n)
while n > 0:
n -= 1
装饰å�Žçš„类和é�™æ€�方法å�¯æ£å¸¸å·¥ä½œï¼Œå�ªä¸�è¿‡å¢žåŠ äº†é¢�外的计时功能:
>>> s = Spam()
>>> s.instance_method(1000000)
<__main__.Spam object at 0x1006a6050> 1000000
0.11817407608032227
>>> Spam.class_method(1000000)
<class '__main__.Spam'> 1000000
0.11334395408630371
>>> Spam.static_method(1000000)
1000000
0.11740279197692871
>>>
讨论¶
å¦‚æžœä½ æŠŠè£…é¥°å™¨çš„é¡ºåº�写错了就会出错。例如,å�‡è®¾ä½ åƒ�下é�¢è¿™æ ·å†™ï¼š
class Spam:
@timethis
@staticmethod
def static_method(n):
print(n)
while n > 0:
n -= 1
é‚£ä¹ˆä½ è°ƒç”¨è¿™ä¸ªé�™æ€�方法时就会报错:
>>> Spam.static_method(1000000)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "timethis.py", line 6, in wrapper
start = time.time()
TypeError: 'staticmethod' object is not callable
>>>
问题在于 @classmethod 和 @staticmethod 实际上并�会创建�直接调用的对象,
而是创建特殊的æ��述器对象(å�‚考8.9å°�节)ã€‚å› æ¤å½“ä½ è¯•ç�€åœ¨å…¶ä»–装饰器ä¸å°†å®ƒä»¬å½“å�šå‡½æ•°æ�¥ä½¿ç”¨æ—¶å°±ä¼šå‡ºé”™ã€‚
ç¡®ä¿�è¿™ç§�装饰器出现在装饰器链ä¸çš„第一个ä½�ç½®å�¯ä»¥ä¿®å¤�这个问题。
当我们在抽象基类ä¸å®šä¹‰ç±»æ–¹æ³•å’Œé�™æ€�方法(å�‚考8.12å°�节)时,这里讲到的知识就很有用了。 ä¾‹å¦‚ï¼Œå¦‚æžœä½ æƒ³å®šä¹‰ä¸€ä¸ªæŠ½è±¡ç±»æ–¹æ³•ï¼Œå�¯ä»¥ä½¿ç”¨ç±»ä¼¼ä¸‹é�¢çš„代ç �:
from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
@classmethod
@abstractmethod
def method(cls):
pass
在这段代ç �ä¸ï¼Œ@classmethod è·Ÿ @abstractmethod 两者的顺åº�æ˜¯æœ‰è®²ç©¶çš„ï¼Œå¦‚æžœä½ è°ƒæ�¢å®ƒä»¬çš„顺åº�就会出错。