亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

閉包函數(shù)

什么是閉包函數(shù)

如果內(nèi)函數(shù)使用了外函數(shù)的局部變量,并且外函數(shù)把內(nèi)函數(shù)返回出來(lái)的過(guò)程叫做閉包,里面的內(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就是一個(gè)閉包函數(shù)
func = outer()

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

下面是一個(gè)復(fù)雜的版本。
inner函數(shù)返回了函數(shù)x 和 y,x 和 y是外函數(shù)的內(nèi)函數(shù),雖然覆蓋了原有的外函數(shù)的局部變量,但是這兩個(gè)函數(shù)本質(zhì)上還是外函數(shù)的布局變量,所以外函數(shù)返回了inner,inner就是一個(gè)閉包函數(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():
# 返回了同級(jí)內(nèi)函數(shù) x y
return x, y

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

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

方法

作用

\__closure__

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

cell_contents

獲取單元格對(duì)象當(dāng)中的閉包函數(shù)

\__closure__

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

# 外函數(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():
# 返回了同級(jí)內(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__測(cè)試這個(gè)幾個(gè)函數(shù)是否是閉包函數(shù)
print(outer.__closure__)
print(func.__closure__)
print(a.__closure__)
print(b.__closure__)

'''
結(jié)果:除了外函數(shù)outer之外都返回了cell對(duì)象,說(shuō)明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單元格對(duì)象的形式展示的,我們并不能看出這個(gè)使用的 元素到底是什么東西,可以使用??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():
# 返回了同級(jí)內(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ù)的特點(diǎn)

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

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

下面的例子中,我們調(diào)用了函數(shù)outer并賦予了參數(shù)val的值為10,但是outer執(zhí)行完之后,outer的val并沒(méi)有被釋放,而是被閉包函數(shù)inner延長(zhǎng)了生命周期,所以val可以一直在inner中按照調(diào)用outer函數(shù)的時(shí)候賦予的值10進(jìn)行運(yùn)算。
因?yàn)閮?nèi)函數(shù)inner使用了外函數(shù)outer的變量val,且outer返回了inner,所以inner是一個(gè)閉包函數(shù)。因?yàn)閕nner是一個(gè)閉包函數(shù),當(dāng)它調(diào)用outer的變量val時(shí)就會(huì)延長(zhǎng)val的生命周期,val就不會(huì)隨著outer的調(diào)用結(jié)束而被釋放
而是存儲(chǔ)在了內(nèi)存當(dāng)中,當(dāng)inner再次使用val時(shí),val就會(huì)將值賦予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ù)中的變量,并對(duì)閉包中的值起到了封裝包保護(hù)的作用,使外部無(wú)法訪問(wèn)。
我們做一個(gè)模擬鼠標(biāo)點(diǎn)擊的事件,可以看得出閉包函數(shù)封裝保護(hù)數(shù)據(jù)的作用。
現(xiàn)在只是一個(gè)普通的函數(shù),它無(wú)法對(duì)我們使用的變量的數(shù)據(jù)進(jìn)行保護(hù),在全局中這個(gè)數(shù)據(jù)可以被隨意的修改。

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

# 全局變量
num = 0

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

# 執(zhí)行點(diǎn)擊事件
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ù)對(duì)數(shù)據(jù)進(jìn)行封裝保護(hù),就不能在全局中隨意的修改我們使用的數(shù)據(jù)。

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

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

# 作為閉包返回
return inner

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

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

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

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

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

相關(guān)文章

最新評(píng)論