<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
如果內函數使用了外函數的區域性變數,並且外函數把內函數返回出來的過程叫做閉包,裡面的內函數是閉包函數。
# 外函數 outer def outer(): # 外函數變數 num var = '外函數區域性變數' # 內函數 inner def inner(): # 內函數使用了外函數的變數 num print('內函數使用了:' + var) # 外函數將使用了外函數的區域性變數的內函數返回 return inner # 返回出的結果就是內函數 inner,現在inner就是一個閉包函數 func = outer() # 執行返回出的 inner 函數 func() # 內函數使用了:外函數區域性變數
下面是一個複雜的版本。
inner函數返回了函數x 和 y,x 和 y是外函數的內函數,雖然覆蓋了原有的外函數的區域性變數,但是這兩個函數本質上還是外函數的佈局變數,所以外函數返回了inner,inner就是一個閉包函數。
inner返回了外函數的x和y函數,x和y函數都是用了外函數的內函數num3,外函數返回inner,inner返回了x和y,所以變相的就是外函數返回了x和y,所以x和y也是閉包函數。
# 外函數 def outer(): # 外函數的區域性變數 x = 1 y = 2 num3 = 3 # 內函數 x 重名變數 x def x(): # 呼叫修改了 變數 num3 nonlocal num3 num3 *= 10 print(num3) # 內函數 y 重名變數y def y(): # 呼叫修改了 變數num3 nonlocal num3 num3 += 10 print(num3) # 內函數inner def inner(): # 返回了同級內函數 x y return x, y # 外函數最終返回了 inner函數 return inner
方法 | 作用 |
__closure__ | 獲取閉包函數使用的區域性變數 |
cell_contents | 獲取單元格物件當中的閉包函數 |
可以使用這個方法判斷一個函數是否是一個閉包函數,因為閉包函數必須要使用外函數的區域性變數,如果返回None就說明這個函數不是閉包函數,如果返回的是一個元組,說明這是一個閉包函數,元組中有cell單元格物件,一個單元格物件表示這個閉包函數使用了幾個外函數的區域性變數。
拿上述版本測試。
# 外函數 def outer(): # 外函數的區域性變數 x = 1 y = 2 num3 = 3 # 內函數 x 重名變數 x def x(): # 呼叫修改了 變數 num3 nonlocal num3 num3 *= 10 print(num3) # 內函數 y 重名變數y def y(): # 呼叫修改了 變數num3 nonlocal num3 num3 += 10 print(num3) # 內函數inner def inner(): # 返回了同級內函數 x y return x, y # 外函數最終返回了 inner函數 return inner # 執行outer返回的結果是inner func = outer() # func == inner # 執行func返回的是 x y 函數 a, b = func() # 使用__closure__測試這個幾個函數是否是閉包函數 print(outer.__closure__) print(func.__closure__) print(a.__closure__) print(b.__closure__) ''' 結果:除了外函數outer之外都返回了cell物件,說明inner x y 都是閉包函數 None (<cell at 0x0000022F246AECA8: function object at 0x0000022F2466C400>, <cell at 0x0000022F247F3558: function object at 0x0000022F24850730>) (<cell at 0x0000022F245D8708: int object at 0x00000000542280B0>,) (<cell at 0x0000022F245D8708: int object at 0x00000000542280B0>,) '''
雖然用__closure__
獲取到了閉包函數使用的元素,但是是以cell單元格物件的形式展示的,我們並不能看出這個使用的 元素到底是什麼東西,可以使用cell_contents
檢視。
# 外函數 def outer(): # 外函數的區域性變數 x = 1 y = 2 num3 = 3 # 內函數 x 重名變數 x def x(): # 呼叫修改了 變數 num3 nonlocal num3 num3 *= 10 print(num3) # 內函數 y 重名變數y def y(): # 呼叫修改了 變數num3 nonlocal num3 num3 += 10 print(num3) # 內函數inner def inner(): # 返回了同級內函數 x y return x, y # 外函數最終返回了 inner函數 return inner # 執行outer返回的結果是inner func = outer() # func == inner # 使用__closure__返回了閉包函數使用的區域性變數 tup = func.__closure__ # 使用 cell_contents 檢視這些區域性變數都是些什麼 res = tup[0].cell_contents print(res) res = tup[1].cell_contents print(res) ''' 結果:可以看到inner 使用的區域性變數使用外函數的內函數 x 和 y None <function outer.<locals>.x at 0x0000018D5A66C400> <function outer.<locals>.y at 0x0000018D5A850730> '''
讓我們回憶一下,函數中建立的變數是一個什麼變數?是一個區域性變數。
區域性變數的生命週期是多久?是等區域性作用結束之後就會被釋放掉。
如果內函數使用了外函數的區域性變數,那麼這個變數就與閉包函數發生了繫結關係,就延長該變數的生命週期。實際上就是記憶體給它儲存了這個值,暫時不釋放。
下面的例子中,我們呼叫了函數outer並賦予了引數val的值為10,但是outer執行完之後,outer的val並沒有被釋放,而是被閉包函數inner延長了生命週期,所以val可以一直在inner中按照呼叫outer函數的時候賦予的值10進行運算。
因為內函數inner使用了外函數outer的變數val,且outer返回了inner,所以inner是一個閉包函數。因為inner是一個閉包函數,當它呼叫outer的變數val時就會延長val的生命週期,val就不會隨著outer的呼叫結束而被釋放
而是儲存在了記憶體當中,當inner再次使用val時,val就會將值賦予inner。
def outer(val): def inner(num): return val + num return inner func = outer(10) res = func(10) print(res) # 20 res = func(20) print(res) # 30
閉包可以優先使用外函數中的變數,並對閉包中的值起到了封裝包保護的作用,使外部無法存取。
我們做一個模擬滑鼠點選的事件,可以看得出閉包函數封裝保護資料的作用。
現在只是一個普通的函數,它無法對我們使用的變數的資料進行保護,在全域性中這個資料可以被隨意的修改。
# 不使用閉包,當函數中呼叫全域性變數時,外部也可以控制變數 # 全域性變數 num = 0 # 點選事件 def click_num(): # 每執行一次數值 +1 global num num += 1 print(num) # 執行點選事件 click_num() # 1 click_num() # 2 click_num() # 3 # 在全域性重新定義了num的值,num的值就被徹底的改變了,但是我們的程式的資料本不該如此。 num = 1231231 click_num() # 1231232 click_num() # 1231233 click_num() # 1231234
現在使用閉包函數對資料進行封裝保護,就不能在全域性中隨意的修改我們使用的資料。
# 我們將需要使用的資料放在外函數中,點選事件作為內函數也放在外函數中,然後作為閉包返回。 def clickNum(): # 需要使用的資料 num = 0 # 內函數(真正執行點選事件的函數) def inner(): # 執行點選事件 nonlocal num num += 1 print(num) # 作為閉包返回 return inner # 返回閉包 click_num = clickNum() # # click_num == inner # 執行點選事件 click_num() # 1 click_num() # 2 click_num() # 3 # 全域性中修改 num 的值 num = 123412341234 # 閉包函數對資料的封裝保護起到了作用 click_num() # 4 click_num() # 5 click_num() # 6
到此這篇關於python 函數進階之閉包函數的文章就介紹到這了,更多相關python 閉包函數內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45