python中的global關鍵字

2021-09-25 14:45:55 字數 4512 閱讀 8836

我最近遇到了乙個關於 python 全域性變數的問題,如下面這個簡單例子裡展示(當然實際**要比這個複雜的多,這裡只是乙個抽象出來當例子)。例子中foo.py定義了函式f,而函式f呼叫了全域性變數a

# foo.py

def f():

print(a)

def main():

global a

a = 5

f()if __name__ == '__main__':

main()

執行上面這個檔案將如預料中的輸出5。在另乙個檔案bar.py中我們引入上面的f,**如下

# bar.py

from foo import f

def main():

f()main()

執行bar.py將報nameerror錯誤。這是因為a被定義在foo.pymain函式中,而當匯入f函式時,foo.pymain函式並未被執行,所以a也沒喲被定義。

traceback (most recent call last):

file "bar.py", line 10, in 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

為了修復上面當問題第一反應是在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 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

python 的global語句的作用只是提示 python 直譯器,被global修飾的變數是乙個全域性變數,利用上面例子裡函式f的反編譯**可以清除的看到這一點:

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被認為是全域性變數。python 中的每乙個函式都擁有乙個__globals__字典變數,該變數實際是函式所屬模組的__dict__變數的引用。所以在bar.py中我們想在bar.main函式中將全域性變數a賦值為4,實際改變的是bar.py__dict__字典變數 (注:而不是定義ffoo.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,然而這個值對函式f來說確是不可見的,因為f.__globals__實際等於foo.__dict__(簡單而言就是命名空間不同)

from foo import f

print(f.__globals__)

假設我們在foo.py所有函式的外部預先定義了全域性變數a,那麼在將函式f匯入時,a會隨著f.__globals__一同被匯入。但這時被匯入的f.__globals__["a"]( 即foo.__dict__["a"]) 和bar.main中賦值的bar.main.__globals__["a"]( 即bar.__dict__["a"]) 仍然不是同乙個變數,即賦值無法改變函式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()

執行bar.py輸出3,而不是 4。

就上述例子而言,如果我們想在bar.py中改變函式f的輸出,則需要直接更新其__globals__變數的值。

# bar.py

from foo import f

def main():

f.__globals__['a'] = 4

f()main()

如上所述,函式的__globals__變數實際是其所屬模組__dict__變數的引用。所以為了達到上面修改全域性變數的目的,也可以直接更新foo.__dict__。修改模組foo的屬性 (attribute) 值即可直接更新foo.__dict__

# bar.py

import foo

from foo import f

def main():

foo.a = 4

f()

如果你曾經使用過執行中給**打補丁的庫,一般就是這麼實現的。直接修改被打補丁的模組的__dict__中特定的物件或函式。、

上面的例子中的函式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)

python 中global的用法

python中定義函式時,若想在函式內部對函式外的變數進行操作,就需要在函式內部宣告其為global。例子1x 1 def func x 2 func print x 輸出 1 此時沒有使用global關鍵字,無法對全域性變數num進行修改 在func函式中並未在x前面加global,所以func函...

python中的global 學習記錄

以往寫python 也沒有用到過這個關鍵字。今天小接觸了一下,把學習到東西分享給大家。看一下下面這一段 num 9 def test2 global num print num num 0 test2 print num 執行結果 函式內,使用了global關鍵字宣告了變數num,注意,這個num因...

Python中global與nonlocal 宣告

如下 a 10 def foo a 100 執行foo 結果 a 還是10 函式中對變數的賦值,變數始終繫結到該函式的區域性命名空間,使用global 語句可以改變這種行為。a 10 def foo global a a 100 a 10 foo a 100 解析名稱時首先檢查區域性作用域,然後由內...