裝飾器類
正如在介紹中提到的,裝飾器是一個可以應用於另一個函式來增強其行為的函式。語法糖相當於以下:my_func = decorator(my_func)
。但是如果 decorator
是一個類呢?語法仍然有效,除了現在 my_func
被 decorator
類的例項替換。如果這個類實現了 __call__()
魔術方法,那麼仍然可以使用 my_func
,就好像它是一個函式:
class Decorator(object):
"""Simple decorator class."""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('Before the function call.')
res = self.func(*args, **kwargs)
print('After the function call.')
return res
@Decorator
def testfunc():
print('Inside the function.')
testfunc()
# Before the function call.
# Inside the function.
# After the function call.
請注意,使用類裝飾器修飾的函式將不再被視為型別檢查透檢視中的函式:
import types
isinstance(testfunc, types.FunctionType)
# False
type(testfunc)
# <class '__main__.Decorator'>
裝飾方法
對於裝飾方法,你需要定義一個額外的 __get__
方法:
from types import MethodType
class Decorator(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('Inside the decorator.')
return self.func(*args, **kwargs)
def __get__(self, instance, cls):
# Return a Method if it is called on an instance
return self if instance is None else MethodType(self, instance)
class Test(object):
@Decorator
def __init__(self):
pass
a = Test()
在裝飾器裡面。
警告!
類裝飾器只為特定函式生成一個例項,因此使用類裝飾器裝飾方法將在該類的所有例項之間共享相同的裝飾器:
from types import MethodType
class CountCallsDecorator(object):
def __init__(self, func):
self.func = func
self.ncalls = 0 # Number of calls of this method
def __call__(self, *args, **kwargs):
self.ncalls += 1 # Increment the calls counter
return self.func(*args, **kwargs)
def __get__(self, instance, cls):
return self if instance is None else MethodType(self, instance)
class Test(object):
def __init__(self):
pass
@CountCallsDecorator
def do_something(self):
return 'something was done'
a = Test()
a.do_something()
a.do_something.ncalls # 1
b = Test()
b.do_something()
b.do_something.ncalls # 2