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

深入解析Python中函數(shù)的參數(shù)與作用域

 更新時(shí)間:2016年03月20日 23:40:44   作者:Flyaway  
這篇文章主要介紹了Python中函數(shù)的參數(shù)與作用域,是Python入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下

傳遞參數(shù)

函數(shù)傳遞參數(shù)時(shí)的一些簡(jiǎn)要的關(guān)鍵點(diǎn):

  • 參數(shù)的傳遞是通過(guò)自動(dòng)將對(duì)象賦值給本地變量名來(lái)實(shí)現(xiàn)的。所有的參數(shù)實(shí)際上都是通過(guò)指針進(jìn)行傳遞的,作為參數(shù)被傳遞的對(duì)象從來(lái)不自動(dòng)拷貝。
  • 在函數(shù)內(nèi)部的參數(shù)名的賦值不會(huì)影響調(diào)用者。
  • 改變函數(shù)的可變對(duì)象參數(shù)的值會(huì)對(duì)調(diào)用者有影響。

實(shí)際上,Python的參數(shù)傳遞模型和C語(yǔ)言的相當(dāng)相似:

不可變參數(shù)”通過(guò)值”進(jìn)行傳遞。像整數(shù)和字符串這樣的對(duì)象是通過(guò)對(duì)象引用而不是拷貝進(jìn)行的,但是因?yàn)椴徽撛趺礃佣疾豢赡茉谠幐淖儾豢勺儗?duì)象,實(shí)際的效果就很像創(chuàng)建了一份拷貝。
可變對(duì)象是通過(guò)”指針”進(jìn)行傳遞的。這就意味著,可變對(duì)象能夠在函數(shù)內(nèi)部進(jìn)行原處修改。
>>避免可變參數(shù)的修改
避免參數(shù)的修改有很多種方式:

傳遞參數(shù)時(shí),傳遞一個(gè)拷貝:

L = [1,2]
changer(L[:])

函數(shù)內(nèi)部進(jìn)行拷貝

def changer(b):
 b=b[:]

將可變對(duì)象轉(zhuǎn)化為不可變對(duì)象

L=[1,2]
changer(tuple(L))

>>對(duì)參數(shù)輸出進(jìn)行模擬
對(duì)于參數(shù)的返回值有一個(gè)小技巧:因?yàn)閞eturn能夠返回任意種類(lèi)的對(duì)象,如果這些值封裝進(jìn)一個(gè)元組或其他的集合類(lèi)型,那么它也能夠返回多個(gè)值。

def multiple(x,y):
 x = 2
 y = [2,4]
 return x,y #Return new values in a tuple

這段代碼貌似返回了兩個(gè)值,其實(shí)只有一個(gè):一個(gè)包含了2個(gè)元素的元組,它的括號(hào)是可以省略的。

特定的參數(shù)匹配模型

>>基礎(chǔ)知識(shí)
匹配模型的大綱:

  • 位置:從左至右進(jìn)行匹配。
  • 關(guān)鍵字參數(shù):通過(guò)參數(shù)名進(jìn)行匹配。(調(diào)用者可以定義哪一個(gè)函數(shù)接受這個(gè)值,通過(guò)在調(diào)用時(shí)使用參數(shù)的變量名,使用name=value這種語(yǔ)法。)
  • 默認(rèn)參數(shù):為沒(méi)有傳入值的參數(shù)定義參數(shù)值。
  • 可變參數(shù):搜集任意多基于位置或關(guān)鍵字的參數(shù)。
  • 可變參數(shù)解包:傳遞任意多的基于位置或關(guān)鍵字的參數(shù)。
  • Keyword-only參數(shù):參數(shù)必須按照名稱傳遞。(只存在于Python3.0中)

>>匹配語(yǔ)法

語(yǔ)法 位置   解釋
func(value) 調(diào)用者 常規(guī)參數(shù):通過(guò)位置進(jìn)行匹配。
func(name=value) 調(diào)用者 關(guān)鍵字參數(shù):通過(guò)變量名匹配。
func(*sequence) 調(diào)用者 以name傳遞所有的對(duì)象,并作為獨(dú)立的基于位置的參數(shù)。
func(**dict) 調(diào)用者 以name成對(duì)的傳遞所有的關(guān)鍵字/值,并作為獨(dú)立的關(guān)鍵字參數(shù)。
def func(name) 函數(shù) 常規(guī)參數(shù):通過(guò)位置或變量名進(jìn)行匹配。
def func(name=value) 函數(shù) 默認(rèn)參數(shù)值,如果在調(diào)用中傳遞的話。
def func(*name) 函數(shù) 匹配并收集(在元組中)所有包含位置的參數(shù)。
def func(**name) 函數(shù) 匹配并收集(在字典中)所有包含位置的參數(shù)。
def func(*args,name) 函數(shù) 參數(shù)必須在調(diào)用中按照關(guān)鍵字傳遞。
def func(*,name=value) 函數(shù)  參數(shù)必須在調(diào)用中按照關(guān)鍵字傳遞。(Python3.0)

相應(yīng)的說(shuō)明:

在函數(shù)的調(diào)用中(表中的前4行),簡(jiǎn)單的通過(guò)變量名位置進(jìn)行匹配,但是使用name=value的形式告訴Python依照變量名進(jìn)行匹配,這些叫做關(guān)鍵字參數(shù)。在調(diào)用中使用*sequence或**dict允許我們?cè)谝粋€(gè)序列或字典中相應(yīng)地封裝任意多的位置相關(guān)或者關(guān)鍵字的對(duì)象,并且在將他們傳遞給函數(shù)的時(shí)候,將它們解包為分開(kāi)的、單個(gè)的參數(shù)。
在函數(shù)的頭部,一個(gè)簡(jiǎn)單的變量名時(shí)通過(guò)位置或變量名進(jìn)行匹配的(取決于調(diào)用者是如何傳遞給它參數(shù)的),但是name=value的形式定義了默認(rèn)的參數(shù)值。*name的形式收集了任意的額外不匹配的參數(shù)到元組中,并且**name的形式將會(huì)手機(jī)額外的關(guān)鍵字參數(shù)到字典中。在Python3.0及其以后的版本中,跟在*name或一個(gè)單獨(dú)的*之后的、任何正式的或默認(rèn)的參數(shù)名稱,都是keyword-only參數(shù),并且必須在調(diào)用時(shí)按照關(guān)鍵字傳遞。
>>細(xì)節(jié)
在使用混合的參數(shù)模型的時(shí)候,Python將會(huì)遵循下面有關(guān)順序的法則。

在函數(shù)調(diào)用中,參數(shù)必須以此順序出現(xiàn):任何位置參數(shù)(value),后面跟著任何關(guān)鍵字參數(shù)(name=value)和*sequence形式的組合,后面跟著**dict形式。
在函數(shù)頭部,參數(shù)必須以此順序出現(xiàn):任何一般參數(shù)(name),緊跟著任何默認(rèn)參數(shù)(name=value),后面是name(在Python3.0中是)形式,后面跟著任何name或name=value keyword-only參數(shù)(Python3.0中),后面跟著**name形式。
在調(diào)用和函數(shù)頭部中,如果出現(xiàn)**arg形式的話,都必須出現(xiàn)在最后。

Python內(nèi)部是使用以下的步驟來(lái)在賦值前進(jìn)行參數(shù)匹配的:

  • 通過(guò)位置分配非關(guān)鍵字參數(shù)。
  • 通過(guò)匹配變量名分配關(guān)鍵字參數(shù)。
  • 其他額外的非關(guān)鍵字分配到*name元組中。
  • 其他額外的關(guān)鍵字參數(shù)分配到**name字典中。
  • 用默認(rèn)值分配給在頭部未得到分配的參數(shù)。
  • 在這之后,Python會(huì)進(jìn)行檢測(cè),確保每個(gè)參數(shù)只傳入了一個(gè)值。如果不是這樣的話,將會(huì)發(fā)生錯(cuò)誤。當(dāng)所有匹配都完成了,Python把傳遞給參數(shù)名的對(duì)象賦值給它們。

>>關(guān)鍵字參數(shù)和默認(rèn)參數(shù)的實(shí)例
如果沒(méi)有使用任何特殊的匹配語(yǔ)法,Python默認(rèn)會(huì)通過(guò)位置從左至右匹配變量名。

def f(a,b,c):
 print(a,b,c)

f(1,2,3)   #Prints 1,2,3

關(guān)鍵字參數(shù)

關(guān)鍵字參數(shù)允許通過(guò)變量名進(jìn)行匹配,而不是通過(guò)位置。

f(c=3,b=2,a=1) #Prints 1,2,3

默認(rèn)參數(shù)

默認(rèn)參數(shù)允許創(chuàng)建函數(shù)可選的參數(shù)。如果沒(méi)有傳入值的話,在函數(shù)運(yùn)行前,參數(shù)就被賦了默認(rèn)值。

def f(a,b=2,c=3):
 print(a,b,c)

f(1)    #Prints 1,2,3
f(1,4)   #Prints 1,4,3
f(1,c=6)   #Prints 1,2,6

關(guān)鍵字參數(shù)和默認(rèn)參數(shù)的混合

def func(spam,eggs,totast=0,ham=0):
 print((spam,eggs,totast=0,ham=0))
func(1,2)     #Ouput:(1,2,0,0)
func(1,ham=1,eggs=0)  #Ouput:(1,0,0,1)
func(spam=1,eggs=0)   #Ouput:(1,0,0,0)
func(toast=1,eggs=2,spam=3) #Ouput:(3,2,1,0)
func(1,2,3,4)    #Ouput:(1,2,3,4)

>>任意參數(shù)的實(shí)例
最后兩種匹配擴(kuò)展,*和**,是讓函數(shù)支持接收任意數(shù)目的參數(shù)的。

收集參數(shù)

在函數(shù)定義中,在元組中收集不匹配的位置參數(shù)。

def f(*args):print(args)

當(dāng)這個(gè)函數(shù)調(diào)用時(shí),Python將所有位置相關(guān)的參數(shù)收集到一個(gè)新的元組中,并將這個(gè)元組賦值給變量args。因此它是一個(gè)一般的元組對(duì)象,能夠進(jìn)行索引或迭代。

**特性類(lèi)似,但是它只對(duì)關(guān)鍵字參數(shù)有效。將這些關(guān)鍵字參數(shù)傳遞給一個(gè)新的字典,這個(gè)字典之后將能夠通過(guò)一般的字典工具進(jìn)行處理。在這種情況下,**允許將關(guān)鍵字參數(shù)轉(zhuǎn)化為字典,你能夠在之后使用鍵調(diào)用進(jìn)行步進(jìn)或字典迭代。

def f(a,*pargs,**kargs):print(a,pargs,kargs)

f(1,2,3,x=1,y=2)  #Prints:1 (2,3) {'x':2,'y':1}

解包參數(shù)

在最新的Python版本中,我們?cè)谡{(diào)用函數(shù)時(shí)能夠使用*語(yǔ)法。在這種情況下,它與函數(shù)定義的意思相反。它會(huì)解包參數(shù)的集合,而不是創(chuàng)建參數(shù)的集合。

def func(a,b,c,d):print(a,b,c,d)
args=(1,2)
args+=(3,4)
func(*args)   #Prints 1,2,3,4

相似的,在函數(shù)調(diào)用時(shí),**會(huì)以鍵/值對(duì)的形式解包一個(gè)字典,使其成為獨(dú)立的關(guān)鍵字參數(shù)。

args={'a':1,'b':2,'c':3}
args['d']=4
func(**args)   #Prints 1,2,3,4

注意:別混淆函數(shù)頭部和函數(shù)調(diào)用時(shí)*/**的語(yǔ)法:在頭部,它意味著收集任意多的參數(shù),而在調(diào)用時(shí),它解包任意數(shù)量的參數(shù)。

應(yīng)用函數(shù)通用性

if <test>:
 action,args=func1,(1,)
else:
 action,args=func2,(1,2,3)
...

action(*args)

>>Python3.0 Keyword-Only參數(shù)
Python3.0把函數(shù)頭部的排序規(guī)則通用化了,允許我們指定keyword-only參數(shù)——即必須只按照關(guān)鍵字傳遞并且不會(huì)由一個(gè)位置參數(shù)來(lái)填充的參數(shù)。

從語(yǔ)法上講,keyword-only參數(shù)編碼為命名的參數(shù),出現(xiàn)在參數(shù)列表中的*args之后。所有這些參數(shù)都必須在調(diào)用中使用關(guān)鍵字語(yǔ)法來(lái)傳遞。

我們也可以在參數(shù)列表中使用一個(gè)*字符,來(lái)表示一個(gè)函數(shù)不會(huì)接受一個(gè)變量長(zhǎng)度的參數(shù)列表,而是仍然期待跟在*后面的所有參數(shù)都作為關(guān)鍵字傳遞。

def kwonly(a,*,b,c):
 print(a,b,c)
kwonly(1,c=3,b=2) #Prints:1,2,3
kwonly(c=3,b=2,a=1) #Prints:1,2,3
kwonly(1,2,3)  #Error!

上述代碼中,b和c必須按照關(guān)鍵字傳遞,不允許其他額外的位置傳遞。

另外,默認(rèn)函數(shù)仍然對(duì)keyword-only參數(shù)有效,所以,實(shí)際上,帶有默認(rèn)值的keyword-only參數(shù)都是可選的,但是,那些沒(méi)有默認(rèn)值的keyword-only參數(shù)真正地變成了函數(shù)必需的keyword-only參數(shù)。

排序規(guī)則 最后,注意keyword-only參數(shù)必須在一個(gè)單個(gè)星號(hào)后指定,而不是兩個(gè)星號(hào)——命名的參數(shù)不能出現(xiàn)在**args任意關(guān)鍵字形式的后面,并且一個(gè)**不能獨(dú)自出現(xiàn)在參數(shù)列表中。這兩種做法將產(chǎn)生錯(cuò)誤。

def kwonly(a,**pargs,b,c)  #Error!
def kwonly(a,**,b,c)   #Error!

這就意味著,在一個(gè)函數(shù)的頭部,keyword-only參數(shù)必須編寫(xiě)在**args任意關(guān)鍵字形式之前,且在*args任意位置形式之后。

實(shí)際上,在函數(shù)調(diào)用中,類(lèi)似的排序規(guī)則也是成立的:當(dāng)傳遞keyword-only參數(shù)的時(shí)候,它們必須出現(xiàn)在一個(gè)**args形式之前。keyword-only參數(shù)可以編寫(xiě)在*arg之前或者之后,并且可能包含在**args中:

def f(a,*b,c=6,**d):print(a,b,c,d)

f(1,*(2,3),**dict(x=4,y=5))  #Prints:1 (2,3) 6 {'x':4,'y':5}
f(1,*(2,3),**dict(x=4,y=5),c=7) #Error!
f(1,*(2,3),c=7,**dict(x=4,y=5)) #Prints:1 (2,3) 7 {'x':4,'y':5}
f(1,c=7,*(2,3),**dict(x=4,y=5)) #Prints:1 (2,3) 7 {'x':4,'y':5}
f(1,*(2,3),**dict(x=4,y=5,c=7)) #Prints:1 (2,3) 7 {'x':4,'y':5}

Python作用域

在一個(gè)Python程序只用變量名時(shí),Python創(chuàng)建、改變或查找變量名都是在所謂的命名空間(一個(gè)保存變量名的地方)中進(jìn)行的。也就是說(shuō),在代碼中變量名被賦值的位置決定了這個(gè)變量名能被訪問(wèn)到的范圍,也即決定了它存在于哪個(gè)命名空間中。

除了打包程序之外,函數(shù)還為程序增加了一個(gè)額外的命名空間層:默認(rèn)情況下,一個(gè)函數(shù)所有變量名都是與函數(shù)的命名空間相關(guān)聯(lián)的。這意味著:

一個(gè)在def內(nèi)的定義的變量能夠在def內(nèi)的代碼使用,不能在函數(shù)的外部應(yīng)用這樣的變量名。
def之中的變量名與def之外的變量名并不沖突,一個(gè)在def之外被賦值的變量X與在這個(gè)def之中賦值的變量X是完全不同的變量。
>>作用域法則
在開(kāi)始編寫(xiě)函數(shù)之前,我們編寫(xiě)的所有代碼都是位于一個(gè)模塊的頂層(也就是說(shuō),并不是嵌套在def之中),所以我們使用的變量名要么是存在于模塊文件本身,要么就是Python內(nèi)置預(yù)先定義好的。函數(shù)定義本地作用域,而模塊定義的全局作用域。這兩個(gè)作用域有如下關(guān)系:

內(nèi)嵌的模塊是全局作用域 每個(gè)模塊都是一個(gè)全局作用域(也就是說(shuō),一個(gè)創(chuàng)建于模塊文件頂層的變量的命名空間)。對(duì)于模塊外部來(lái)說(shuō),該模塊的全局變量就成為了這個(gè)模塊對(duì)象的屬性,但是在這個(gè)模塊中能夠像簡(jiǎn)單的變量一樣使用。
全局作用域的作用范圍僅限于單個(gè)文件 這里的全局指的是在一個(gè)文件的頂層的變量名僅對(duì)于這個(gè)文件內(nèi)部的代碼而言是全局的。在Python中是沒(méi)有基于一個(gè)單個(gè)的、無(wú)所不包的情景文件的全局作用域的。
每次對(duì)函數(shù)的調(diào)用都創(chuàng)建了一個(gè)新的本地作用域
賦值的變量名除非聲明為全局變量或非局部變量,否則均為局部變量
所有的變量名都可以歸納為本地、全局或者內(nèi)置的
>>變量名解析:LEGB原則
Python的變量名解析機(jī)制有時(shí)稱為L(zhǎng)EGB法則,當(dāng)在函數(shù)中使用未認(rèn)證的變量名時(shí),Python搜索4個(gè)作用域:

  • 本地作用域(L)
  • 上一層結(jié)構(gòu)中def或lambda的本地作用域(E)(其實(shí)就是函數(shù)嵌套的情況)
  • 全局作用域(G)
  • 最后是內(nèi)置作用域(B)

Python按順序在上面4個(gè)作用域中查找變量,并且在第一個(gè)能夠找到這個(gè)變量名的地方停下來(lái),如果在這4個(gè)作用域中都沒(méi)找到,Python會(huì)報(bào)錯(cuò)。

這里需要強(qiáng)調(diào)的是,上面四個(gè)作用域是函數(shù)中代碼的搜索過(guò)程,也就是說(shuō),在函數(shù)中能直接使用上一層中的變量!

s=10
def times(x,y):
 x=s
 return x*y

times(3,4) #return 40 not 12

>>內(nèi)置作用域
內(nèi)置作用域是通過(guò)一個(gè)名為builtin的標(biāo)準(zhǔn)模塊來(lái)實(shí)現(xiàn)的,但是這個(gè)變量名自身并沒(méi)有放入內(nèi)置作用域內(nèi),所以必須導(dǎo)入這個(gè)文件才能夠使用它。在Python3.0中,可以使用以下的代碼來(lái)查看到底預(yù)定義了哪些變量:

import builtins
dir(builtins)

因此,事實(shí)上有兩種方法可以引用一個(gè)內(nèi)置函數(shù):通過(guò)LEGB法則帶來(lái)的好處,或者手動(dòng)導(dǎo)入builtin模塊。其中第二種方法在一些復(fù)雜的任務(wù)里是很有用的,因?yàn)橐恍┚植孔兞坑锌赡軙?huì)覆蓋內(nèi)置的變量或函數(shù)。再次強(qiáng)調(diào)的是,LEGB法則只使它找到的第一處變量名的地方生效!

global語(yǔ)句

global語(yǔ)句是一個(gè)命名空間的聲明,它告訴Python解釋器打算生成一個(gè)或多個(gè)全局變量,也就是說(shuō),存在于整個(gè)模塊內(nèi)部作用域(命名空間)的變量名。關(guān)于全局變量名:

全局變量是位于模塊文件內(nèi)部頂層的變量名。
全局變量如果是在函數(shù)內(nèi)部被賦值的話,必須經(jīng)過(guò)聲明。
全局變量名在函數(shù)的內(nèi)部不經(jīng)過(guò)聲明也可以被引用。
global語(yǔ)句包含了關(guān)鍵字global,其后跟著一個(gè)或多個(gè)由逗號(hào)分開(kāi)的變量名。當(dāng)在函數(shù)主題被賦值或引用時(shí),所有列出來(lái)的變量名將被映射到整個(gè)模塊的作用域內(nèi)。 舉個(gè)例子:

X=88
def func():
 global X
 X = 99

func()
print(X) #Prints 99

作用域和嵌套函數(shù)

這部分內(nèi)容是關(guān)于LEGB查找法則中E這一層的,它包括了任意嵌套函數(shù)內(nèi)部的本地作用域。嵌套作用域有時(shí)也叫做靜態(tài)嵌套作用域。實(shí)際上,嵌套是一個(gè)語(yǔ)法上嵌套的作用域,它是對(duì)應(yīng)于程序源代碼的物理結(jié)構(gòu)上的嵌套結(jié)構(gòu)。

>>嵌套作用域的細(xì)節(jié)
對(duì)于一個(gè)函數(shù)來(lái)說(shuō):

一個(gè)引用(X)首先在本地(函數(shù)內(nèi))作用域查找變量名X;之后會(huì)在代碼的語(yǔ)法上嵌套了的函數(shù)中的本地作用域,從內(nèi)到外查找;之后查找當(dāng)前的全局作用域(模塊文件);最后在內(nèi)置作用域內(nèi)(模塊builtin)。全局聲明將會(huì)直接從全局(模塊文件)作用域進(jìn)行搜索。其實(shí)就是從引用X的地方開(kāi)始,一層一層網(wǎng)上搜索,直到找到的第一個(gè)X。
在默認(rèn)情況下,一個(gè)賦值(X=value)創(chuàng)建或修改了變量名X的當(dāng)前作用域。如果X在函數(shù)內(nèi)部聲明為全局變量,它將會(huì)創(chuàng)建或改變變量名X為整個(gè)模塊的作用域。另一方面,如果X在函數(shù)內(nèi)部聲明為nonlocal,賦值會(huì)修改最近的嵌套函數(shù)的本地作用域中的名稱X。
>>嵌套作用域舉例

X = 99
def f1():
 X = 88
 def f2():
 print(X)
 f2()
f1() #Prints 88:enclosing def local

首先需要說(shuō)明的是,上面這段代碼是合法的,def是一個(gè)簡(jiǎn)單的執(zhí)行語(yǔ)句,可以出現(xiàn)在任意其他語(yǔ)句能夠出現(xiàn)的地方,包括嵌套在另一個(gè)def之中。代碼中,f2是在f1中定義的函數(shù),在此情況下,f2是一個(gè)臨時(shí)函數(shù),僅在f1內(nèi)部執(zhí)行的過(guò)程中存在(并且只對(duì)f1中的代碼可見(jiàn))。通過(guò)LEGB查找法則,f2內(nèi)的X自動(dòng)映射到了f1的X。

值得注意的是,這個(gè)嵌套作用域查找在嵌套的函數(shù)已經(jīng)返回后也是有效的。

X = 99
def f1():
 X = 88
 def f2():
 print(X) #Remember X in enclosing def scope
 return f2 #Return f2 but don't call it

action = f1() #Make return function
action() #Call it now:Prints 88

上述代碼中,不管調(diào)用幾次action函數(shù),返回值都是88,f2記住了f1中嵌套作用域中的X,盡管此時(shí)f1已經(jīng)不處于激活的狀態(tài)。

工廠函數(shù)

上述這些行為有時(shí)叫做閉合(closure)或者工廠函數(shù)——一個(gè)能夠記住嵌套作用域的變量值的函數(shù),即使那個(gè)作用域也許已經(jīng)不存在了。通常來(lái)說(shuō),使用類(lèi)來(lái)記錄狀態(tài)信息時(shí)更好的選擇,但是像這樣的工廠函數(shù)也提供了一種替代方案。 具體的例子:

def maker(N):
 def action(X):
 return X ** N
 return action

f=maker(2) #Pass 2 to N
f(3) #Pass 3 to X,N remembers 2: 3**2,Return 9
f(4) #return 4**2

g=maker(3) #g remembers 3,f remembers 2
g(3) #return 27
f(3) #return 9

從上面代碼中可以看到,f和g函數(shù)分別記錄了不同的N值,也就是記錄了不同的狀態(tài),每一次對(duì)這個(gè)工廠函數(shù)進(jìn)行賦值,都會(huì)得到一個(gè)狀態(tài)信息的集合,每個(gè)函數(shù)都有自己的狀態(tài)信息,由maker中的變量N保持。

作用域與帶有循環(huán)變量的默認(rèn)參數(shù)相比較

在已給出的法則中有一個(gè)值得注意的特例:如果lambda或者def在函數(shù)中定義,嵌套在一個(gè)循環(huán)之中,并且嵌套的函數(shù)引用了一個(gè)上層作用域的變量,該變量被循環(huán)所改變,所有在這個(gè)循環(huán)中產(chǎn)生的函數(shù)都將會(huì)有相同的值——在最后一次循環(huán)中完成時(shí)被引用變量的值。具體的例子:

def makeActions():
 acts=[]
 for i in range(5): #Tries to remember each i
 acts.append(lambda x: i ** x) #All remember same last it
 return acts

盡管是在嘗試創(chuàng)建一個(gè)函數(shù)列表,使得每個(gè)函數(shù)擁有不同的狀態(tài)值,但是事實(shí)上,這個(gè)列表中的函數(shù)的狀態(tài)值都是一樣的,是4。因?yàn)榍短鬃饔糜蛑械淖兞吭谇短椎暮瘮?shù)被調(diào)用時(shí)才進(jìn)行查找,所以它們實(shí)際上記住的是同樣的值(在最后一次循環(huán)迭代中循環(huán)變量的值)。

為了能讓這類(lèi)代碼能夠工作,必須使用默認(rèn)參數(shù)把當(dāng)前的值傳遞給嵌套作用域的變量。因?yàn)槟J(rèn)參數(shù)是在嵌套函數(shù)創(chuàng)建時(shí)評(píng)估的(而不是在其稍后調(diào)用時(shí)),每一個(gè)函數(shù)記住了自己的變量i的值。

def makeActions():
 acts=[]
 for i in range(5): #Use default instead
 acts.append(lambda x,i=i: i ** x) #Remember current i
 return acts
{

nonlocal語(yǔ)句

事實(shí)上,在Python3.0中,我們也可以修改嵌套作用域變量,只要我們?cè)谝粭lnonlocal語(yǔ)句中聲明它們。使用這條語(yǔ)句,嵌套的def可以對(duì)嵌套函數(shù)中的名稱進(jìn)行讀取和寫(xiě)入訪問(wèn)。nonlocal應(yīng)用于一個(gè)嵌套的函數(shù)的作用域中的一個(gè)名稱,而不是所有def之外的全局模塊作用域——它們可能只存在于一個(gè)嵌套的函數(shù)中,并且不能由一個(gè)嵌套的def中第一次賦值創(chuàng)建。

換句話說(shuō),nonlocal即允許對(duì)嵌套的函數(shù)作用域中的名稱變量賦值,并且把這樣的名稱作用域查找限制在嵌套的def。

>>nonlocal基礎(chǔ)

def func():
 nonlocal name1,name2...

這條語(yǔ)句允許一個(gè)嵌套函數(shù)來(lái)修改在一個(gè)語(yǔ)法嵌套函數(shù)的作用域中定義的一個(gè)或多個(gè)名稱。在Python 2.X中,當(dāng)一個(gè)函數(shù)def嵌套在另一個(gè)函數(shù)中,嵌套的函數(shù)可以引用上一層函數(shù)中定義的各種變量,但是不能修改它們。在Python3.0中,在一條nonlocal語(yǔ)句中聲明嵌套的作用域,使得嵌套的函數(shù)能夠賦值,并且由此也能夠修改這樣的名稱。

除了允許修改嵌套的def中的名稱,nonlocal語(yǔ)句還加快了引用——就像global語(yǔ)句一樣,nonlocal使得對(duì)該語(yǔ)句中列出的名稱的查找從嵌套的def的作用域中開(kāi)始,而不是從聲明函數(shù)的本地作用域開(kāi)始,也就是說(shuō),nonlocal也意味著”完全略過(guò)我的本地作用域”。

實(shí)際上,當(dāng)執(zhí)行到nonlocal語(yǔ)句的時(shí)候,nonlocal中列出的名稱必須在一個(gè)嵌套的def中提前定義過(guò),否則,將會(huì)產(chǎn)生一個(gè)錯(cuò)誤。直接效果和global很相似:global意味著名稱位于上一層的模塊中,nonlocal意味著它們位于一個(gè)上一層的def函數(shù)中。nonlocal甚至更加嚴(yán)格——作用域查找只限定在嵌套的def。也就是說(shuō),nonlocal只能出現(xiàn)在嵌套的def中,而不能在模塊的全局作用域中或def之外的內(nèi)置作用域中。

當(dāng)在一個(gè)函數(shù)中使用的時(shí)候,global和nonlocal語(yǔ)句都在某種程度上限制了查找規(guī)則:

global使得作用域查找從嵌套的模塊的作用域開(kāi)始,并且允許對(duì)那里的名稱賦值。如果名稱不存在與該模塊中,作用域查找繼續(xù)到內(nèi)置作用域,但是,對(duì)全局名稱的賦值總是在模塊作用域中創(chuàng)建或修改它們。
nonlocal限制作用域查找只是嵌套的def,要求名稱已經(jīng)存在于那里,并且允許對(duì)它們賦值。作用域查找不會(huì)繼續(xù)到全局或內(nèi)置作用域。
>>nonlocal應(yīng)用
使用nonlocal進(jìn)行修改

def tester(start):
 state = start #each call gets its own state
 def nested(label):
 nonlocal state #remember state in enclosing scope
 print(label,state)
 state+=1 #Allowed to change it if onolocal
 return nested


F = tester(0) #Increments state on each call
F('spam') #Prints:spam 0
F('ham') #Prints:ham 1
F('eggs') #Prints:eggs 2

邊界情況

當(dāng)執(zhí)行一條nonlocal語(yǔ)句時(shí),nonlocal名稱必須已經(jīng)在一個(gè)嵌套的def作用域中賦值過(guò),否則將會(huì)得到一個(gè)錯(cuò)誤。
nonlocal限制作用域查找僅為嵌套的def,nonlocal不會(huì)在嵌套的模塊的全局作用域或所有def之外的內(nèi)置作用域中查找。

相關(guān)文章

  • Python使用socket_TCP實(shí)現(xiàn)小文件下載功能

    Python使用socket_TCP實(shí)現(xiàn)小文件下載功能

    這篇文章主要介紹了Python使用socket_TCP實(shí)現(xiàn)小文件下載功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • python中必要的名詞解釋

    python中必要的名詞解釋

    在本篇文章里小編給大家整理的是關(guān)于python中必要的名詞解釋以及相關(guān)知識(shí)點(diǎn),有興趣的朋友們學(xué)習(xí)下。
    2019-11-11
  • Python延遲綁定問(wèn)題原理及解決方案

    Python延遲綁定問(wèn)題原理及解決方案

    這篇文章主要介紹了Python延遲綁定問(wèn)題原理及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 解決django后臺(tái)樣式丟失,css資源加載失敗的問(wèn)題

    解決django后臺(tái)樣式丟失,css資源加載失敗的問(wèn)題

    今天小編就為大家分享一篇解決django后臺(tái)樣式丟失,css資源加載失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • Python開(kāi)發(fā)加薪利器之Docker的使用實(shí)踐

    Python開(kāi)發(fā)加薪利器之Docker的使用實(shí)踐

    docker利用容器技術(shù),獨(dú)立運(yùn)行一個(gè)或者一組應(yīng)用,docker是基于go語(yǔ)言開(kāi)發(fā),docker鏡像好比是一個(gè)模版,可以通過(guò)這個(gè)模版來(lái)創(chuàng)建容器服務(wù),今天通過(guò)本文給大家分享Docker的使用實(shí)踐,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • 聊聊Python中end=和sep=的區(qū)別

    聊聊Python中end=和sep=的區(qū)別

    這篇文章主要介紹了Python中end=和sep=的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-05-05
  • 如何使用virtualenv管理python環(huán)境

    如何使用virtualenv管理python環(huán)境

    這篇文章主要介紹了如何使用virtualenv管理python環(huán)境,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • Python實(shí)現(xiàn)經(jīng)典算法拓?fù)渑判颉⒆址ヅ渌惴ê妥钚∩蓸?shù)實(shí)例

    Python實(shí)現(xiàn)經(jīng)典算法拓?fù)渑判?、字符串匹配算法和最小生成?shù)實(shí)例

    這篇文章主要介紹了Python實(shí)現(xiàn)經(jīng)典算法拓?fù)渑判?、字符串匹配算法和最小生成?shù)實(shí)例,拓?fù)渑判?、字符串匹配算法和最小生成?shù)是計(jì)算機(jī)科學(xué)中常用的數(shù)據(jù)結(jié)構(gòu)和算法,它們?cè)诮鉀Q各種實(shí)際問(wèn)題中具有重要的應(yīng)用價(jià)值,需要的朋友可以參考下
    2023-08-08
  • python commands模塊的適用方式

    python commands模塊的適用方式

    這篇文章主要介紹了python commands模塊的適用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Pytorch?使用Google?Colab訓(xùn)練神經(jīng)網(wǎng)絡(luò)深度學(xué)習(xí)

    Pytorch?使用Google?Colab訓(xùn)練神經(jīng)網(wǎng)絡(luò)深度學(xué)習(xí)

    本文以VOC數(shù)據(jù)集為例,因此在訓(xùn)練的時(shí)候沒(méi)有修改classes_path等,如果是訓(xùn)練自己的數(shù)據(jù)集,各位一定要注意修改classes_path等其它參數(shù)
    2022-04-04

最新評(píng)論