本文實例講述了Python閉包思想與用法。分享給大家供大家參考,具體如下:
淺談 python 的閉包思想
首先 python的閉包使用方法是:在方法A內添加方法B,然后return
方法B 注意,return
的時候不要添加任何參數,包括()
這樣,通過調用方法A 返回的是一個function 對象,如 demo=方法A 可以直接使用 demo(參數) 將調用方法B 這里不用關注方法B的方法名,
只需要關注參數就可以了,demo(參數) 這里的參數其實就是閉包的方法B的參數,可以多個參數或者元祖一起使用。
其次 在Python中創建一個閉包可以歸結為以下三點:
- 閉包函數必須有內嵌函數
- 內嵌函數需要引用該嵌套函數上一級namespace中的變量
- 閉包函數必須返回內嵌函數
對,沒錯,python的裝飾器就是使用了閉包。
好吧,最后再舉個栗子:
1
2
3
4
5
6
7
8
|
def test1(prefix): def test2(name): print ( 'test2閉包內:' ,name) def test3( * name1): print ( 'test3 閉包內:' ,name1) return test3 m = test1( 'prefix' ) m( "haha" , 'heihei' ) |
打印結果:
D:\python\python.exe D:/Python_day/day1.py
test3 閉包內: ('haha', 'heihei')
這個例子說明,當函數 test1 的生命周期結束之后,test1('prefix')
中的參數 prefix 這個變量依然存在,生命周期不會隨著函數調用結束而消失。
為啥要用閉包呢? 感覺這個功能一般啊,畢竟回調函數是死的,只能回調一個,但是有個函數就是能生成無數個對象,嗯,是的,這玩意和類的功能有點相似。閉包可以被理解為一個只讀的對象,你可以給他傳遞一個屬性,但它只能提供給你一個執行的接口,這就牽扯到的另一個特性:惰性求值
如:
1
2
3
4
5
6
7
8
9
10
11
12
|
# 偽代碼示意 class QuerySet( object ): def __init__( self , sql): self .sql = sql self .db = Mysql.connect().corsor() # 偽代碼 def __call__( self ): return db.execute( self .sql) def query(sql): return QuerySet(sql) result = query( "select name from user_app" ) if time > now: print result # 這時才執行數據庫訪問 |
上面這個不太恰當的例子展示了通過閉包完成惰性求值的功能,但是上面query返回的結果并不是函數,而是具有函數功能的類。有興趣的可以去看看Django的queryset的實現,原理類似。
還有另一種用處:需要對某個函數的參數提前賦值的情況,當然在Python中已經有了很好的解決訪問 functools.parial
,但是用閉包也能實現。
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
def partial( * * outer_kwargs): def wrapper(func): def inner( * args, * * kwargs): for k, v in outer_kwargs.items(): kwargs[k] = v return func( * args, * * kwargs) return inner return wrapper @partial (age = 15 ) def say(name = None , age = None ): print name, age say(name = "the5fire" ) # 當然用functools比這個簡單多了 # 只需要: functools.partial(say, age=15)(name='the5fire') |
對于工廠函數的理解,感覺和閉包類似,在創建主函數后返回的對象,可以直接傳參使用,其實這里返回的對象,就是一個類。
希望本文所述對大家Python程序設計有所幫助。
原文鏈接:https://blog.csdn.net/guoxinjie17/article/details/77838851