【根據廖雪峰python教程整理】
由於函式也是乙個物件,而且函式物件可以被賦值給變數,所以,通過變數也能呼叫該函式。
>>> def now():
... print '2013-12-25'
...>>> f = now
>>> f()
2013-12-25
函式物件有乙個__name__
屬性,可以拿到函式的名字:
>>> now.__name__
'now'
>>> f.__name__
'now'
現在,假設我們要增強now()
函式的功能,比如,在函式呼叫前後自動列印日誌,但又不希望修改
now()
函式的定義,這種在**執行期間動態增加功能的方式,稱之為「裝飾器」(decorator
)。
本質上,decorator
就是乙個返回函式的高階函式。所以,我們要定義乙個能列印日誌的
decorator
,可以定義如下:
def log(func):
print 'call %s():' % func.__name__
return func(*args, **kw)
觀察上面的log
,因為它是乙個
decorator
,所以接受乙個函式作為引數,並返回乙個函式。我們要借助
python的@
語法,把
decorator
置於函式的定義處:
@log
def now():
print '2013-12-25'
呼叫now()
函式,不僅會執行
now()
函式本身,還會在執行
now()
函式前列印一行日誌:
>>> now()
call now():
2013-12-25
把@log
放到now()
函式的定義處,相當於執行了語句:
now = log(now)
由於log()
是乙個decorator
,返回乙個函式,所以,原來的
now()
函式仍然存在,只是現在同名的
now變數指向了新的函式,於是呼叫
now()
將執行新函式,即在
log()
函式中返回的
函式。
(*args, **kw)
,因此,
函式可以接受任意引數的呼叫。在
函式內,首先列印日誌,再緊接著呼叫原始函式。
如果decorator
本身需要傳入引數,那就需要編寫乙個返回
decorator
的高階函式,寫出來會更複雜。比如,要自定義
log的文字:
def log(text):
def decorator(func):
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return decorator
這個3層巢狀的
decorator
用法如下:
@log('execute')
def now():
print '2013-12-25'
執行結果如下:
>>> now()
execute now():
2013-12-25
和兩層巢狀的decorator
相比,3
層巢狀的效果是這樣的:
>>> now = log('execute')(now)
我們來剖析上面的語句,首先執行log('execute')
,返回的是
decorator
函式,再呼叫返回的函式,引數是
now函式,返回值最終是
函式。
以上兩種decorator
的定義都沒有問題,但還差最後一步。因為我們講了函式也是物件,它有
__name__
等屬性,但你去看經過
decorator
裝飾之後的函式,它們的
__name__
已經從原來的
'now'
變成了:
>>> now.__name__
函式名字就是
,所以,需要把原始函式的
__name__
等屬性複製到
函式中,否則,有些依賴函式簽名的**執行就會出錯。
這樣的**,
python
內建的functools.wraps
就是幹這個事的,所以,乙個完整的
decorator
的寫法如下:
import functools
def log(func):
@functools.wraps(func)
print 'call %s():' % func.__name__
return func(*args, **kw)
或者針對帶引數的decorator
:import functools
def log(text):
def decorator(func):
@functools.wraps(func)
print '%s %s():' % (text, func.__name__)
return func(*args, **kw)
return decorator
import functools是匯入
functools
模組。模組的概念稍候講解。現在,只需記住在定義
的前面加上
@functools.wraps(func)
即可。
小結:
在物件導向(oop
)的設計模式中,
decorator
被稱為裝飾模式。
oop的裝飾模式需要通過繼承和組合來實現,而
python
除了能支援
oop的
decorator
外,直接從語法層次支援
decorator
。python
的decorator
可以用函式實現,也可以用類實現。
decorator可以增強函式的功能,定義起來雖然有點複雜,但使用起來非常靈活和方便。
Python學習筆記 函式式程式設計 高階函式
根據廖雪峰python教程整理 高階函式英文叫higher order function 什麼是高階函式?我們以實際 為例子,一步一步深入概念。一 變數可以指向函式 以python 內建的求絕對值的函式 abs 為例,呼叫該函式用以下 abs 10 10 但是,如果只寫abs 呢?abs 可見,ab...
Python學習筆記之 函式式程式設計
函式式程式設計的乙個特點就是,允許把函式本身作為引數傳入另乙個函式,還允許返回乙個函式。變數可以指向函式 f abs f 10 10函式名也是變數 abs 10 abs 10 traceback most recent call last file line 1,in typeerror int o...
python學習筆記(四) 函式式程式設計
1 高階函式 高階函式 higher order function 1 變數可以指向函式 函式本身也可以賦值給變數。2 函式名也是變數 指向函式的變數。3 傳入函式 變數能夠指向函式,函式的引數能接收變數,乙個函式就可以接收另乙個函式作為引數。接收兩個引數 函式,iterable map 將傳入的函...