2018-6-5
先看一個例子:
>>> def now():
print('2015-3-25')
>>> f = now
>>> f()
2015-3-25
現在我們可以用__name__
拿到函數的名字。
如果現在要增強now()
的功能,例如在函數調用前後自動打印日誌,但又不希望修改now()
函數的定義,這種在代碼運行期間動態增加功能的方式,稱之爲“裝飾器”(Decorator)。
—————-此處不能明白,先略過
下面給出的是定義一個能打印日誌的decorator
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
#上面的@log相當於執行了語句
#now = log(now)
def now():
print('2015-3-25')
>>> now()
call now():
2015-3-25
這段代碼實現的是調用now()
函數,實現:
1、運行now()
函數本身
2、在運行now()
函數之前打印一行日誌:call now():
裝飾器給出的解釋爲:
由於log()是一個decorator,返回一個函數,所以,原來的now()函數仍然存在,只是現在同名的now變量指向了新的函數,於是調用now()將執行新函數,即在log()函數中返回的wrapper()函數。
wrapper()函數的參數定義是(*args, **kw),因此,wrapper()函數可以接受任意參數的調用。在wrapper()函數內,首先打印日誌,再緊接着調用原始函數。
我的理解這段代碼是這樣運行的:
1.@log
即now = log(now)
log(now)
的意思是:now()
函數傳入log()
中,返回一個wrapper()
函數。這個wrapper()
函數是什麼呢?我們看print('call %s():' % func.__name__)
,其中有一個%s
,其意思是將%func.__name__
插入到%s
這個位置,也就變成了call now():
。然後一個新的變量now指向了這個返回的wrapper()
函數。
2.在wrapper()
函數內部,先完成了打印日誌的功能,然後return func(*args, **kw)
中調用了now()
函數,即實現print('2015-3-25')
。
2018-6-6
啊~五環
今天看到一篇稱@log
這樣的東西爲語法糖的文章。
可以用來精簡裝飾器代碼。
Python裝飾器——田小計劃
如果裝飾器本身需要支持參數,那麼裝飾器就需要多一層的內嵌函數。
裝飾器調用順序
裝飾器是可疊加的。對於Python中的”@”語法糖,裝飾器的調用順序與使用 @ 語法糖聲明的順序相反。