Python3學習筆記 | 十九、Python的函數-作用域
- 2019 年 10 月 6 日
- 筆記
部分設備閱讀本文會存在程式碼錯亂的情況,可點擊閱讀原文鏈接到部落格中進行查看
一、Python作用域基礎
作用域針對的是變數。在使用同一個變數名時,會出現作用域問題。如右邊的x,在函數里與函數外是不同的變數。 • 一個def內定義的變數名能夠被def內部使用。不能在函數外部引用這個變數名。 • def內的變數名與def外的變數名並不衝突。在def內賦值的與def外賦值的相同變數名是不同的變數。 變數名有如下三種不同作用域: 1、全局:在def外定義的變數名是全局變數 2、本地:在def內部定義的叫做本地變數 3、其它:嵌套def時,各自的變數也是獨立的。
二、作用域法則
內嵌的模組是全局作用域,全局作用域的作用範圍僅限於單個文件,每次的函數的調用都創建了一個新的本地作用域,賦值的變數名除非聲明全局變數或非本地變數(Python3.x有非本地變數說法),否則均為本地變數。所有其它的變數名都可以歸納為本地、全局或者內置。
變數名使用時,查找順序:LEGB L:本地變數名 - 在本地是否使用此變數名賦值過。 E:上一層結構中def或lambda的本地變數名 - 上一層是否使用此變數名賦值過。 G:全局變數名 - 在整個文件里是否對變數名賦值過。 B:內置變數名 - Python內部是否存在此變數名。 要是都找不到相應變數名,就會報錯。
內置變數:exit、open等。 >>> l = 'global'; e = 'global'; g = 'global' #全局變數 >>>def myenclosefunc(): ... e = 'enclose';l = 'enclose' #enclose func變數 ... def mylocalfunc(): ... l = 'local' #本地變數 ... print('in local: l={},e={},g={}'.format(l,e,g)) ... mylocalfunc() ... print('in enclose: l={},e={},g={}'.format(l,e,g)) ... >>> myenclosefunc() in local: l=local,e=enclose,g=global in enclose: l=enclose,e=enclose,g=global >>> print('in global: l={},e={},g={}'.format(l,e,g)) in global: l=global,e=global,g=global
三、global語句
在函數內,想改變全局變數,可以使用global語句來定義此變數為全局變數,如下所示。
>>> g = 'global' >>> l = 'global' >>> def myfunc(): ... global g ... g = 'local' ... l = 'local' ... >>> g,l ('global', 'global') >>> myfunc() >>> g,l ('local', 'global')
在myfunc函數里,都重新賦值了g與l,但在函數執行後,只有g改變了。當使用global g 之後,當前函數里所使用的所有對變數g的更改都會對全局變數g進行更改。 除了這個方法,還有引用自己的方法(交互模式里,可以import main)與sys.modules的方法(可以使用引用過的所有模組,交互模式里本身可以用main方式),具體如下。
>>> x = 2 >>> import __main__ >>> __main__.x 2 >>> def glob(): ... __main__.x += 1 ... >>> glob() >>> x 3
>>> x = 2 >>> import sys >>> sys.modules['__main__'].x 2 >>> def glob(): ... sys.modules['__main__'].x += 1 ... >>> glob() >>> x 3
四、作用域與嵌套函數
被嵌套函數的作用域也是上級函數里:
>>> def outer(): ... def inner(): ... print('inner') ...
在這裡,想調用inner函數,必須是在函數outer裡面,不能直接使用。這個時候,我們可以返回內部函數的方法來提取內部函數:
>>> def outer(): ... def inner(): ... print('inner') ... return inner() ... >>> func1 = outer() inner
工廠函數
工廠函數為:根據要求的對象,一個能夠記住嵌套作用域的變數值的函數。這種功能,使用類可以更好的實現,但使用函數也能簡單實現。
>>> def funcl(x): ... def action(y): #嵌套函數 ... return x ** y #返回x ** y的值 ... return action #返回嵌套的函數 ... >>> a = funcl(3) #定義x值為3後的嵌套函數賦值 >>> a(2) 9 >>> a(3) 27
可以使用lambda,把之前函數變為:
>>> def func(x): ... return lambda y :x ** y ... >>> a = func(3) >>> a(2) 9
關於lamdba的使用可以參考:https://www.cnblogs.com/evening/archive/2012/03/29/2423554.html
循環變數
>>> def makeAction(): ... acts = [] ... for i in range(5): ... acts.append(lambda x:i ** x) ... return acts ...
執行後,返回值可能不是我們想像的結果:
>>> funclist = makeAction() >>> funclist[0](2) 16 >>> funclist[4](2) 16
原因在於,i x的時候,i的值取的是for循環結束後的最後一個(4)。我們需要寫成lambda x, i=i: i x,這樣,lambda里的i是本地變數,跟for循環里的i不衝突,優化後如下:
>>> def makeAction(): ... acts = [] ... for i in range(5): ... acts.append(lambda x,i = i : i ** x) ... return acts ... >>> funclist = makeAction() >>> funclist[0](2) 0 >>> funclist[2](2) 4 >>> funclist[4](2) 16
五、nonlocal語句
nonlocal關鍵字用來在函數或其他作用域中使用外層(非全局)變數,更多用法可以參考https://blog.csdn.net/youngbit007/article/details/64905070
>>> x = 1 #全局變數x為1 >>> y = 1 #全局變數y為1 >>> def printxy(): ... x = 2 #printxy里的本地變數x為2 ... y = 2 #printxy里的本地變數y為2 ... def setxy(): ... nonlocal x #設定x為nonlocal ... global y #設定y為global ... x =3 ... y =3 ... setxy() ... print(x) ... print(y) ... >>> printxy() 3 #printxy里的x為3 2 #printxy里的y沒變,仍為2 >>> x,y (1, 3) #全局變數x沒變,y變為3