9.10 為類和靜態(tài)方法提供裝飾器

2018-02-24 15:26 更新

問題

你想給類或靜態(tài)方法提供裝飾器。

解決方案

給類或靜態(tài)方法提供裝飾器是很簡單的,不過要確保裝飾器在 @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

裝飾后的類和靜態(tài)方法可正常工作,只不過增加了額外的計時功能:

>>> 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
>>>

討論

如果你把裝飾器的順序?qū)戝e了就會出錯。例如,假設(shè)你像下面這樣寫:

class Spam:
    @timethis
    @staticmethod
    def static_method(n):
        print(n)
        while n > 0:
            n -= 1

那么你調(diào)用這個鏡頭方法時就會報錯:

>>> 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 實(shí)際上并不會創(chuàng)建可直接調(diào)用的對象, 而是創(chuàng)建特殊的描述器對象(參考8.9小節(jié))。因此當(dāng)你試著在其他裝飾器中將它們當(dāng)做函數(shù)來使用時就會出錯。 確保這種裝飾器出現(xiàn)在裝飾器鏈中的第一個位置可以修復(fù)這個問題。 當(dāng)我們在抽象基類中定義類方法和靜態(tài)方法(參考8.12小節(jié))時,這里講到的知識就很有用了。 例如,如果你想定義一個抽象類方法,可以使用類似下面的代碼:

from abc import ABCMeta, abstractmethod
class A(metaclass=ABCMeta):
    @classmethod
    @abstractmethod
    def method(cls):
        pass

在這段代碼中,@classmethod@abstractmethod 兩者的順序是有講究的,如果你調(diào)換它們的順序就會出錯。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號