python內部函數、閉包共同之處在於都是以函數作為參數傳遞到函數,不同之處在於返回與調用有所區別。
python內部函數示例:
def test(*args): def add(*args): # 顯示的調用外部函數的參數 return args return add(*args) # 返回內部函數的直接調用 運行結果如下: test(1,2,3) (1,2,3)
內部函數直接引用外部函數參數,外部函數test顯示的返回內部函數add的調用。
當需要在函數內部多次執行復雜任務時,內部函數非常有用,從而避免了循環和代碼的堆疊重復。
內部函數可以看作是一個閉包。閉包是一個可以由另一個函數動態生成的函數,並且可以改變和存儲函數外創建的變量的值。
python閉包示例:
def test(a): def add(): # 沒用引用外部函數的參數 return "it's a callable %s" % a # 直接在內部函數使用外部函數的參數 return add # 返回內部函數本身,不返回內部函數調用 運行結果如下: a1 = test(1) # 動態生成的一個可以記錄外部變量的函數 <function __main__.add> a1() # 調用此函數 it's a callable 1 test(1)() # 本身調用過程,先動態生成一個函數再進行調用 it's a callable 1
裝飾器實質上是一個函數,它把一個函數作為輸入並且返回另外一個函數,在裝飾器中,通常使用下面這些python技巧:
*args 和 **kwargs
閉包
作為參數的函數
python裝飾器示例:
def test(func): # 將函數作為參數進行傳遞 def add(*args,**kwargs): print “it's a d” return func(*args,**kwargs) # 內部函數進行相關操作以後,返回傳遞函數的調用 return add def func(a,b): return a+b 運行結果如下: test(func) # 將func作為函數傳遞進test函數進行裝飾 <function __main__.add> # 裝飾後的函數,類似閉包 test(func)(1,2) # 顯示的對裝飾後的函數進行調用 it's a d # 中間被裝飾的過程被print出來 3 更簡單的方法調用裝飾器 @test # 同一個函數可以調用多個裝飾器,執行過程中不分先後順序 def func(a,b): return a+b 無論傳入test()的函數func是什麼,裝飾器都會返回一個新的函數,其中包含test增加的額外語句。
實際上,裝飾器並不需要執行函數func中的代碼,只是在結束前函數add調用函數func以得到的func返回的結果和附加代碼的結果
裝飾器本身需要傳遞參數的時候:
def test(cmd): # 將參數傳遞 def exc(func): # 第二步進行函數作為參數傳遞 def add(*args,**kwargs): print "it's a %s" % cmd print "begin" return func(*args,**kwargs) return add return exc 運行結果如下: test('haha') <function __main__.exc> test('haha')(func)(1,2) # 調用裝飾器返回結果 it's a haha begin 3 更簡單的方法調用 @test('haha') # test函數進行了參數傳遞 def func(a,b): return a+b
python裝飾器注意事項:
對func進行裝飾以後,func的函數命名空間發生了變化
執行 func.__name__ add
如何指向原來的命名空間呢?python自帶了functools庫直接調用則行
import functools def test(func): @functools.wraps(func) def add(*args,**kwargs): print "it's a decorator" return func(*args,**kwargs) return add @test def func(a,b): return a+b 再次運行,查看命名空間 func.__name__ func # 返回了本身