深入了解python全局變量,局部變量和命名空間
Python 使用全局和局部變量的方式是特立獨(dú)行的。雖然在許多或大多數(shù)其他編程語言中,如果未另行聲明,變量將被視為全局變量,而 Python 則以相反的方式處理變量。如果沒有另外聲明,它們是本地的。這種方法背后的驅(qū)動(dòng)原因是全局變量通常是不好的做法,應(yīng)該避免。在大多數(shù)情況下,您想使用全局變量,最好使用參數(shù)將值放入函數(shù)或返回值以將其取出。與許多其他程序結(jié)構(gòu)一樣,Python 也通過設(shè)計(jì)強(qiáng)加了良好的編程習(xí)慣。
因此,當(dāng)您在函數(shù)定義中定義變量時(shí),默認(rèn)情況下它們是該函數(shù)的局部變量。也就是說,您對函數(shù)體中的此類變量所做的任何操作都不會(huì)影響函數(shù)外的其他變量,即使它們具有相同的名稱。換句話說,函數(shù)體是這樣一個(gè)變量的范圍,即這個(gè)名稱與其值相關(guān)聯(lián)的封閉上下文。
所有變量都有塊的作用域,它們在那里被聲明和定義。它們只能在聲明點(diǎn)之后使用。
簡單說一下:變量不必也不能以在 Java 或 C 等編程語言中聲明的方式聲明。Python 中的變量通過定義它們來隱式聲明,即第一次分配值到一個(gè)變量,這個(gè)變量被聲明并自動(dòng)具有必須分配給它的對象的數(shù)據(jù)類型。如果您在理解這一點(diǎn)時(shí)遇到問題,請參閱我們關(guān)于數(shù)據(jù)類型和變量的章節(jié),請參閱左側(cè)的鏈接。
函數(shù)中的全局和局部變量
在下面的示例中,我們想演示如何在函數(shù)體內(nèi)使用全局值:
def f (): print ( s ) s = “我愛夏天的巴黎!” f ()
輸出:
我愛夏天的巴黎!
在調(diào)用函數(shù) f() 之前,變量 s 被定義為字符串“我愛夏天的巴黎!”。f() 的主體僅由“print(s)”語句組成。由于沒有局部變量 s,即沒有賦值給 s,將使用全局變量 s 的值。所以輸出將是字符串“我愛夏天的巴黎!”。問題是,如果我們在函數(shù) f() 中改變 s 的值會(huì)發(fā)生什么?它也會(huì)影響全局變量嗎?我們在下面的一段代碼中對此進(jìn)行了測試:
def f (): s = "我愛倫敦!" 打印( s ) s = “我愛巴黎!” f () 打印( s )
輸出:
我愛倫敦!
我愛巴黎!
如果我們將第一個(gè)示例與第二個(gè)示例結(jié)合起來,即我們首先使用 print() 函數(shù)訪問 s,希望獲得全局值,然后為其分配一個(gè)新值呢?給它賦值,意味著 - 正如我們之前所說的 - 創(chuàng)建一個(gè)局部變量 s。因此,我們會(huì)將 s 作為同一范圍內(nèi)的全局變量和局部變量,即函數(shù)體。幸運(yùn)的是,Python 不允許這種歧義。因此,它會(huì)引發(fā)錯(cuò)誤,正如我們在以下示例中所見:
def f (): print ( s ) s = “我愛倫敦!” 打印( s ) s = “我愛巴黎!” f ()
輸出:
UnboundLocalError Traceback (最近一次調(diào)用最后一次)
<ipython-input-3-d7a23bc83c27> in <module>
5
6 s = “我愛巴黎!”
----> 7 f ( )
<ipython-input-3-d7a23bc83c27> in f ()
1 def f ( ) :
----> 2 print ( s )
3 s = “我
愛倫敦!” 4 打印( s )
5
UnboundLocalError:賦值前引用了局部變量“s”
變量不能在函數(shù)內(nèi)既是局部的又是全局的。由于在 f() 內(nèi)部為 s 賦值,因此 Python 決定我們需要一個(gè)局部變量,因此在 s 定義之前的第一個(gè)打印語句拋出了上面的錯(cuò)誤信息。任何在函數(shù)內(nèi)部更改或創(chuàng)建的變量都是局部變量,如果它沒有被聲明為全局變量。要告訴 Python,我們要使用全局變量,我們必須使用關(guān)鍵字“global”明確說明這一點(diǎn),如下例所示:
def f (): global s print ( s ) s = "只在春天,但倫敦也很棒!" 打印( s ) s = "我在巴黎找課程!" f () 打印( s )
輸出:
我正在巴黎尋找課程!
只在春天,但倫敦也很棒!
只在春天,但倫敦也很棒!
函數(shù)調(diào)用完成后,不能從外部訪問函數(shù)的局部變量。這是上一個(gè)例子的延續(xù):
def f (): s = "我在全球范圍內(nèi)不為人知" 打印( s ) f () 打印( s )
輸出:
我在全球不為人知
只在春天,但倫敦也很棒!
以下示例顯示了局部和全局變量以及函數(shù)參數(shù)的狂野組合:
def foo ( x , y ): 全局 a a = 42 x , y = y , x b = 33 b = 17 c = 100 打印( a , b , x , y ) a , b , x , y = 1 , 15 , 3 , 4 foo ( 17 , 4 ) 打印( a , b , x , y )
輸出:
42 17 4 17
42 15 3 4
嵌套函數(shù)中的全局變量
如果我們在嵌套函數(shù)中使用 global 關(guān)鍵字,我們現(xiàn)在將檢查會(huì)發(fā)生什么。以下示例顯示了在各種范圍內(nèi)使用變量“city”的情況:
def f (): city = "Hamburg" def g (): global city city = "Geneva" print ( "調(diào)用前g:" + city ) print ( "現(xiàn)在調(diào)用g:" ) g () print ( "調(diào)用后g: " + 城市) f () print ( "主城的值:" + city )
輸出:
之前打電話給g:漢堡
現(xiàn)在調(diào)用 g:
打電話后g:漢堡
主要城市價(jià)值:日內(nèi)瓦
我們可以看到嵌套函數(shù) g 中的 global 語句不會(huì)影響函數(shù) f 的變量“city”,即它保持其值“Hamburg”。我們還可以從這個(gè)例子中推斷出,在調(diào)用 f() 之后,模塊命名空間中存在一個(gè)變量 'city',其值為 'Geneva'。這意味著嵌套函數(shù)中的 global 關(guān)鍵字不會(huì)影響其封閉命名空間的命名空間!這與我們在前一章中發(fā)現(xiàn)的一致:在函數(shù)內(nèi)部定義的變量是局部變量,除非它明確標(biāo)記為全局變量。換句話說,我們可以在任何封閉作用域中引用一個(gè)變量名,但我們只能在局部作用域中通過賦值重新綁定變量名,或者通過使用全局聲明在模塊全局作用域中重新綁定變量名。我們還需要一種方法來訪問其他作用域的變量。這樣做的方法是非局部定義,我們將在下一章解釋。
非局部變量
Python3 引入了非局部變量作為一種新的變量。非局部變量與全局變量有很多共同點(diǎn)。與全局變量的一個(gè)區(qū)別在于,無法通過使用非局部語句來更改模塊范圍內(nèi)的變量,即未在函數(shù)內(nèi)部定義的變量。我們在以下兩個(gè)示例中展示了這一點(diǎn):
def f (): 全球 城市 打印( city ) city = "法蘭克福" f ()
輸出:
法蘭克福
該程序是正確的,并返回“Frankfurt”作為輸出。我們將在以下程序中將“全局”更改為“非本地”:
def f (): 非本地 城市 打印( city ) city = "法蘭克福" f ()
輸出:
文件“<ipython-input-9-97bb311dfb80>” ,第2
行 非本地城市
^
語法錯(cuò)誤:未找到非本地“城市”的綁定
這表明非局部綁定只能在嵌套函數(shù)內(nèi)部使用。必須在封閉的函數(shù)作用域中定義非局部變量。如果變量未在封閉函數(shù)作用域中定義,則變量不能在嵌套作用域中定義。這是與“全局”語義的另一個(gè)區(qū)別。
def f (): city = "Munich" def g (): nonlocal city city = "Zurich" print ( "調(diào)用前g:" + city ) print ( "現(xiàn)在調(diào)用g:" ) g () print ( "調(diào)用后g: " + 城市) city = "Stuttgart" f () print ( "'city' in main:" + city )
輸出:
打電話之前 g: 慕尼黑
現(xiàn)在調(diào)用 g:
撥打 g 后:蘇黎世
主要的“城市”:斯圖加特
在前面的例子中,變量 'city' 是在調(diào)用 g 之前定義的。如果沒有定義,我們會(huì)得到一個(gè)錯(cuò)誤:
高清 ?F (): #city = “慕尼黑” 高清 g ^ (): 外地 市 城市 = “蘇黎世” 打?。ā昂艚心∏埃骸? + 城市) 打印(“立即致電G:” ) g ^ () 打?。ā昂蠛艚?g: " + city ) city = "Stuttgart" f () print ( "'city' in main:" + city )
輸出:
文件“<ipython-input-11-5417be93b6a6>” ,第4
行 非本地城市
^
語法錯(cuò)誤:未找到非本地“城市”的綁定
該程序運(yùn)行良好 - 如果我們將“非本地”更改為“全局”,在 f - 內(nèi)有或沒有 'city = "Munich"' 行:
def f (): #city = "Munich" def g (): global city city = "Zurich" print ( "Before call g:" + city ) print ( "Calling g now:" ) g () print ( "After 調(diào)用g:" )呼叫 g: " + city ) city = "Stuttgart" f () print ( "'city' in main:" + city )
輸出:
打電話之前:斯圖加特
現(xiàn)在調(diào)用 g:
撥打 g 后:蘇黎世
主要的“城市”:蘇黎世
然而有一個(gè)巨大的不同:全局 x 的值現(xiàn)在發(fā)生了變化!
相關(guān)文章
簡單介紹Python的Django框架的dj-scaffold項(xiàng)目
這篇文章主要介紹了簡單介紹Python的Django框架的dj-scaffold項(xiàng)目,用于輔助Django框架的目錄設(shè)置,需要的朋友可以參考下2015-05-05Python可視化工具如何實(shí)現(xiàn)動(dòng)態(tài)圖表
這篇文章主要介紹了Python可視化工具如何實(shí)現(xiàn)動(dòng)態(tài)圖表,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10python matplotlib實(shí)現(xiàn)雙Y軸的實(shí)例
今天小編就為大家分享一篇python matplotlib實(shí)現(xiàn)雙Y軸的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-02-02python argparse命令行參數(shù)解析(推薦)
Python argparse模塊是解析命令行參數(shù)的首選方法。解析命令行參數(shù)是一個(gè)非常常見的任務(wù),Python腳本根據(jù)傳遞的值來執(zhí)行和操作2021-06-06TensorFlow Session使用的兩種方法小結(jié)
今天小編就為大家分享一篇TensorFlow Session使用的兩種方法小結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07在Linux中通過Python腳本訪問mdb數(shù)據(jù)庫的方法
這篇文章主要介紹了在Linux中通過Python腳本訪問mdb數(shù)據(jù)庫的方法,本文示例基于debian系的Linux系統(tǒng),需要的朋友可以參考下2015-05-05Python中round()函數(shù)實(shí)現(xiàn)數(shù)值的四舍五入
這篇文章主要給大家介紹了關(guān)于Python中round()函數(shù)實(shí)現(xiàn)數(shù)值的四舍五入,round()是python自帶的一個(gè)函數(shù),用于數(shù)字的四舍五入,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05Python實(shí)現(xiàn)希爾排序算法的原理與用法實(shí)例分析
這篇文章主要介紹了Python實(shí)現(xiàn)希爾排序算法,簡單講述了希爾排序的原理并結(jié)合具體實(shí)例形式分析了Python希爾排序的具體實(shí)現(xiàn)方法與使用技巧,需要的朋友可以參考下2017-11-11