【Python】裝飾器

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.@lognow = 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中的”@”語法糖,裝飾器的調用順序與使用 @ 語法糖聲明的順序相反。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章