欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python 函數(shù)進階之閉包函數(shù)

 更新時間:2022年04月18日 15:58:16   作者:小可愛呦  
這篇文章主要介紹了python 函數(shù)進階之閉包函數(shù),內(nèi)函數(shù)使用了外函數(shù)的局部變量,并且外函數(shù)把內(nèi)函數(shù)返回出來的過程叫做閉包,里面的內(nèi)函數(shù)是閉包函數(shù),下文相關介紹需要的小伙伴可以參考一下

閉包函數(shù)

什么是閉包函數(shù)

如果內(nèi)函數(shù)使用了外函數(shù)的局部變量,并且外函數(shù)把內(nèi)函數(shù)返回出來的過程叫做閉包,里面的內(nèi)函數(shù)是閉包函數(shù)。

# 外函數(shù) outer
def outer():
# 外函數(shù)變量 num
var = '外函數(shù)局部變量'

# 內(nèi)函數(shù) inner
def inner():
# 內(nèi)函數(shù)使用了外函數(shù)的變量 num
print('內(nèi)函數(shù)使用了:' + var)

# 外函數(shù)將使用了外函數(shù)的局部變量的內(nèi)函數(shù)返回
return inner

# 返回出的結(jié)果就是內(nèi)函數(shù) inner,現(xiàn)在inner就是一個閉包函數(shù)
func = outer()

# 執(zhí)行返回出的 inner 函數(shù)
func() # 內(nèi)函數(shù)使用了:外函數(shù)局部變量

下面是一個復雜的版本。
inner函數(shù)返回了函數(shù)x 和 y,x 和 y是外函數(shù)的內(nèi)函數(shù),雖然覆蓋了原有的外函數(shù)的局部變量,但是這兩個函數(shù)本質(zhì)上還是外函數(shù)的布局變量,所以外函數(shù)返回了inner,inner就是一個閉包函數(shù)。
inner返回了外函數(shù)的x和y函數(shù),x和y函數(shù)都是用了外函數(shù)的內(nèi)函數(shù)num3,外函數(shù)返回inner,inner返回了x和y,所以變相的就是外函數(shù)返回了x和y,所以x和y也是閉包函數(shù)。

# 外函數(shù)
def outer():
# 外函數(shù)的局部變量
x = 1
y = 2
num3 = 3

# 內(nèi)函數(shù) x 重名變量 x
def x():
# 調(diào)用修改了 變量 num3
nonlocal num3
num3 *= 10
print(num3)

# 內(nèi)函數(shù) y 重名變量y
def y():
# 調(diào)用修改了 變量num3
nonlocal num3
num3 += 10
print(num3)

# 內(nèi)函數(shù)inner
def inner():
# 返回了同級內(nèi)函數(shù) x y
return x, y

# 外函數(shù)最終返回了 inner函數(shù)
return inner

判斷是否是閉包函數(shù)

方法

作用

\__closure__

獲取閉包函數(shù)使用的局部變量

cell_contents

獲取單元格對象當中的閉包函數(shù)

\__closure__

可以使用這個方法判斷一個函數(shù)是否是一個閉包函數(shù),因為閉包函數(shù)必須要使用外函數(shù)的局部變量,如果返回None就說明這個函數(shù)不是閉包函數(shù),如果返回的是一個元組,說明這是一個閉包函數(shù),元組中有cell單元格對象,一個單元格對象表示這個閉包函數(shù)使用了幾個外函數(shù)的局部變量。
拿上述版本測試。

# 外函數(shù)
def outer():
# 外函數(shù)的局部變量
x = 1
y = 2
num3 = 3

# 內(nèi)函數(shù) x 重名變量 x
def x():
# 調(diào)用修改了 變量 num3
nonlocal num3
num3 *= 10
print(num3)

# 內(nèi)函數(shù) y 重名變量y
def y():
# 調(diào)用修改了 變量num3
nonlocal num3
num3 += 10
print(num3)

# 內(nèi)函數(shù)inner
def inner():
# 返回了同級內(nèi)函數(shù) x y
return x, y

# 外函數(shù)最終返回了 inner函數(shù)
return inner


# 執(zhí)行outer返回的結(jié)果是inner
func = outer() # func == inner

# 執(zhí)行func返回的是 x y 函數(shù)
a, b = func()

# 使用__closure__測試這個幾個函數(shù)是否是閉包函數(shù)
print(outer.__closure__)
print(func.__closure__)
print(a.__closure__)
print(b.__closure__)

'''
結(jié)果:除了外函數(shù)outer之外都返回了cell對象,說明inner x y 都是閉包函數(shù)
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>,)
'''

cell_contents

雖然用??__closure__??獲取到了閉包函數(shù)使用的元素,但是是以cell單元格對象的形式展示的,我們并不能看出這個使用的 元素到底是什么東西,可以使用??cell_contents??查看。

# 外函數(shù)
def outer():
# 外函數(shù)的局部變量
x = 1
y = 2
num3 = 3

# 內(nèi)函數(shù) x 重名變量 x
def x():
# 調(diào)用修改了 變量 num3
nonlocal num3
num3 *= 10
print(num3)

# 內(nèi)函數(shù) y 重名變量y
def y():
# 調(diào)用修改了 變量num3
nonlocal num3
num3 += 10
print(num3)

# 內(nèi)函數(shù)inner
def inner():
# 返回了同級內(nèi)函數(shù) x y
return x, y

# 外函數(shù)最終返回了 inner函數(shù)
return inner


# 執(zhí)行outer返回的結(jié)果是inner
func = outer() # func == inner


# 使用__closure__返回了閉包函數(shù)使用的局部變量
tup = func.__closure__

# 使用 cell_contents 查看這些局部變量都是些什么
res = tup[0].cell_contents
print(res)
res = tup[1].cell_contents
print(res)

'''
結(jié)果:可以看到inner 使用的局部變量使用外函數(shù)的內(nèi)函數(shù) x 和 y
None
<function outer.<locals>.x at 0x0000018D5A66C400>
<function outer.<locals>.y at 0x0000018D5A850730>
'''

閉包函數(shù)的特點

讓我們回憶一下,函數(shù)中創(chuàng)建的變量是一個什么變量?是一個局部變量。
局部變量的生命周期是多久?是等局部作用結(jié)束之后就會被釋放掉。

如果內(nèi)函數(shù)使用了外函數(shù)的局部變量,那么這個變量就與閉包函數(shù)發(fā)生了綁定關系,就延長該變量的生命周期。實際上就是內(nèi)存給它存儲了這個值,暫時不釋放。

下面的例子中,我們調(diào)用了函數(shù)outer并賦予了參數(shù)val的值為10,但是outer執(zhí)行完之后,outer的val并沒有被釋放,而是被閉包函數(shù)inner延長了生命周期,所以val可以一直在inner中按照調(diào)用outer函數(shù)的時候賦予的值10進行運算。
因為內(nèi)函數(shù)inner使用了外函數(shù)outer的變量val,且outer返回了inner,所以inner是一個閉包函數(shù)。因為inner是一個閉包函數(shù),當它調(diào)用outer的變量val時就會延長val的生命周期,val就不會隨著outer的調(diào)用結(jié)束而被釋放
而是存儲在了內(nèi)存當中,當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

閉包函數(shù)的意義

閉包可以優(yōu)先使用外函數(shù)中的變量,并對閉包中的值起到了封裝包保護的作用,使外部無法訪問。
我們做一個模擬鼠標點擊的事件,可以看得出閉包函數(shù)封裝保護數(shù)據(jù)的作用。
現(xiàn)在只是一個普通的函數(shù),它無法對我們使用的變量的數(shù)據(jù)進行保護,在全局中這個數(shù)據(jù)可以被隨意的修改。

# 不使用閉包,當函數(shù)中調(diào)用全局變量時,外部也可以控制變量

# 全局變量
num = 0

# 點擊事件
def click_num():
# 每執(zhí)行一次數(shù)值 +1
global num
num += 1
print(num)

# 執(zhí)行點擊事件
click_num() # 1
click_num() # 2
click_num() # 3

# 在全局重新定義了num的值,num的值就被徹底的改變了,但是我們的程序的數(shù)據(jù)本不該如此。
num = 1231231

click_num() # 1231232
click_num() # 1231233
click_num() # 1231234

現(xiàn)在使用閉包函數(shù)對數(shù)據(jù)進行封裝保護,就不能在全局中隨意的修改我們使用的數(shù)據(jù)。

# 我們將需要使用的數(shù)據(jù)放在外函數(shù)中,點擊事件作為內(nèi)函數(shù)也放在外函數(shù)中,然后作為閉包返回。
def clickNum():
# 需要使用的數(shù)據(jù)
num = 0

# 內(nèi)函數(shù)(真正執(zhí)行點擊事件的函數(shù))
def inner():
# 執(zhí)行點擊事件
nonlocal num
num += 1
print(num)

# 作為閉包返回
return inner

# 返回閉包
click_num = clickNum() # # click_num == inner

# 執(zhí)行點擊事件
click_num() # 1
click_num() # 2
click_num() # 3

# 全局中修改 num 的值
num = 123412341234

# 閉包函數(shù)對數(shù)據(jù)的封裝保護起到了作用
click_num() # 4
click_num() # 5
click_num() # 6

到此這篇關于python 函數(shù)進階之閉包函數(shù)的文章就介紹到這了,更多相關python 閉包函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論