python中的global關(guān)鍵字的使用方法
摘要
- global 標(biāo)志實(shí)際上是為了提示 python 解釋器,表明被其修飾的變量是全局變量。這樣解釋器就可以從當(dāng)前空間 (current scope) 中讀寫相應(yīng)變量了。
- Python 的全局變量是模塊 (module) 級別的
- 每個 python 函數(shù)擁有對應(yīng)的 __globals__ 字典,該字典與函數(shù)所屬模塊的 __dict__ 字典完全相同。函數(shù)的全局變量也會從這個字典中獲取
- 注:上面三句話的意思就是,python 解釋器發(fā)現(xiàn)函數(shù)中的某個變量被 global 關(guān)鍵字修飾,就去函數(shù)的 __globals__ 字典變量中尋找(因?yàn)?python 中函數(shù)也是一等對象);同時,一個模塊中每個函數(shù)的 __globals__ 字典變量都是模塊 __dict__ 字典變量的引用,二者值完全相同。
- 避免全局變量將使得程序更容易被調(diào)試,同時也能提升程序的可讀性
- 使用到的全局變量只是作為引用,不在函數(shù)中修改它的值的話,不需要加global關(guān)鍵字. 使用到的全局變量,需要在函數(shù)中修改的話,就涉及到歧義問題. 因此在函數(shù)中修改全局變量的話需要加global關(guān)鍵字
動機(jī)
我最近遇到了一個關(guān)于 python 全局變量的問題,如下面這個簡單例子里展示(當(dāng)然實(shí)際代碼要比這個復(fù)雜的多,這里只是一個抽象出來當(dāng)例子)。例子中 foo.py 定義了函數(shù) f,而函數(shù) f 調(diào)用了全局變量 a:
# foo.py def f(): print(a) def main(): global a a = 5 f() if __name__ == '__main__': main()
運(yùn)行上面這個文件將如預(yù)料中的輸出5。在另一個文件 bar.py 中我們引入上面的 f,代碼如下
# bar.py from foo import f def main(): f() main()
運(yùn)行 bar.py 將報 NameError 錯誤。這是因?yàn)?nbsp;a 被定義在 foo.py 的 main 函數(shù)中,而當(dāng)導(dǎo)入 f 函數(shù)時, foo.py 的 main 函數(shù)并未被運(yùn)行,所以 a 也沒喲被定義。
Traceback (most recent call last): File "bar.py", line 10, in <module> main() File "bar.py", line 7, in main f() File "foo.py", line 5, in f print(a) NameError: global name 'a' is not defined
定義全局變量 a
為了修復(fù)上面當(dāng)問題第一反應(yīng)是在 bar.py 中定義全局變量 a,這樣 f 就可以找到變量 a 了,如下面的代碼:
# bar.py from foo import f def main(): global a a = 4 f() main()
然而依舊會報錯,黑人問號臉???
Traceback (most recent call last): File "/tmp/example/bar.py", line 13, in <module> main() File "/tmp/example/bar.py", line 9, in main f() File "/tmp/example/foo.py", line 5, in f print(a) NameError: global name 'a' is not defined
函數(shù)的 __globals__ 屬性與 python 的 global 語句
python 的 global 語句的作用只是提示 python 解釋器,被 global 修飾的變量是一個全局變量,利用上面例子里函數(shù) f 的反編譯代碼可以清除的看到這一點(diǎn):
import dis from foo import f dis.dis(f)
5 0 LOAD_GLOBAL 0 (print) 2 LOAD_GLOBAL 1 (a) 4 CALL_FUNCTION 1 6 POP_TOP 8 LOAD_CONST 0 (None) 10 RETURN_VALUE
面可以看出變量 a 被認(rèn)為是全局變量。Python 中的每一個函數(shù)都擁有一個 __globals__ 字典變量,該變量實(shí)際是函數(shù)所屬模塊的 __dict__ 變量的引用。所以在 bar.py 中我們想在 bar.main 函數(shù)中將全局變量 a 賦值為4,實(shí)際改變的是 bar.py 的 __dict__ 字典變量 (注:而不是定義 f 的 foo.py 的 __dict__ 字典變量)
# bar.py def main(): global a a = 4 print(main.__globals__.keys()) print(main.__globals__['a']) dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'foo', 'f', 'dis', 'main', 'a']) 4
上面的代碼輸出了 main.__globals__ (即 bar.__dict__ ) 中全局變量 a 的值是4,然而這個值對函數(shù) f 來說確是不可見的,因?yàn)?nbsp;f.__globals__ 實(shí)際等于 foo.__dict__ (簡單而言就是命名空間不同)
from foo import f print(f.__globals__)
假設(shè)我們在 foo.py 所有函數(shù)的外部預(yù)先定義了全局變量 a ,那么在將函數(shù) f 導(dǎo)入時,a 會隨著 f.__globals__ 一同被導(dǎo)入。但這時被導(dǎo)入的 f.__globals__["a"] ( 即 foo.__dict__["a"] ) 和 bar.main 中賦值的 bar.main.__globals__["a"] ( 即 bar.__dict__["a"] ) 仍然不是同一個變量,即賦值無法改變函數(shù) f 的輸出,如下面的例子所示。
# foo.py a = 3 def f(): print(a) def main(): global a a = 5 f() if __name__ == '__main__': main()
# bar.py from foo import f def main(): global a a = 4 f() main()
運(yùn)行 bar.py 輸出3,而不是 4。
修改函數(shù)全局變量的值:更新 globals
就上述例子而言,如果我們想在 bar.py 中改變函數(shù) f 的輸出,則需要直接更新其 __globals__ 變量的值。
# bar.py from foo import f def main(): f.__globals__['a'] = 4 f() main()
- 模塊的 dict 變量和猴子布丁 (monkey-patching)
如上所述,函數(shù)的 __globals__ 變量實(shí)際是其所屬模塊 __dict__ 變量的引用。所以為了達(dá)到上面修改全局變量的目的,也可以直接更新 foo.__dict__ 。修改模塊 foo 的屬性 (attribute) 值即可直接更新 foo.__dict__ 。
# bar.py import foo from foo import f def main(): foo.a = 4 f()
如果你曾經(jīng)使用過運(yùn)行中給代碼打補(bǔ)丁的庫,一般就是這么實(shí)現(xiàn)的。直接修改被打補(bǔ)丁的模塊的 __dict__ 中特定的對象或函數(shù)。、
輸入使得函數(shù)變得更加容易測試
上面的例子中的函數(shù) f 如果接受輸入變量的話,而不是使用全局變量,代碼將更容易被測試。同時可讀性也更好,出了問題也更容易 debug。
# foo.py def f(a): print(a) def main(): a = 5 f(a) if __name__ == '__main__': main()
# bar.py from foo import f def main(): a = 3 f(a)
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python global全局變量函數(shù)詳解
- python中g(shù)lobal與nonlocal比較
- python global關(guān)鍵字的用法詳解
- Python中 Global和Nonlocal的用法詳解
- python中g(shù)lobal用法實(shí)例分析
- 對python多線程與global變量詳解
- Python中關(guān)鍵字global和nonlocal的區(qū)別詳解
- Python 內(nèi)置函數(shù)globals()和locals()對比詳解
- Python全局變量與global關(guān)鍵字常見錯誤解決方案
- Python全局變量關(guān)鍵字global的簡單使用
相關(guān)文章
Python+Django實(shí)現(xiàn)接口測試工具的示例代嗎
本文主要介紹了Python+Django實(shí)現(xiàn)接口測試工具,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07python中文分詞,使用結(jié)巴分詞對python進(jìn)行分詞(實(shí)例講解)
下面小編就為大家?guī)硪黄猵ython中文分詞,使用結(jié)巴分詞對python進(jìn)行分詞的實(shí)例講解。有比較好的參考價值,希望能給大家做個參考。一起跟隨小編過來看看吧2017-11-11基于Python3.6+splinter實(shí)現(xiàn)自動搶火車票
這篇文章主要為大家詳細(xì)介紹了基于Python3.6+splinter實(shí)現(xiàn)自動搶火車票,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-09-09Python pandas.DataFrame調(diào)整列順序及修改index名的方法
這篇文章主要介紹了Python pandas.DataFrame調(diào)整列順序及修改index名的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-06-06如何取消pyecharts繪制地圖時默認(rèn)顯示小圓點(diǎn)標(biāo)識
這篇文章主要介紹了如何取消pyecharts繪制地圖時默認(rèn)顯示小圓點(diǎn)標(biāo)識,文章內(nèi)容介紹詳細(xì)具有一定的參考價值?需要的小伙伴可以參考一下2022-04-04詳解python環(huán)境安裝selenium和手動下載安裝selenium的方法
這篇文章主要介紹了詳解python環(huán)境安裝selenium和手動下載安裝selenium的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Python實(shí)現(xiàn)arctan換算角度的示例
本文主要介紹了Python實(shí)現(xiàn)arctan換算角度的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03