Python中通過函數對象創建全局變量


先看下面這段代碼,顯然無法work. 因為代碼試圖在TestVariableScope()中引用一個沒有被定義的變量a.所以必須報錯,如下圖-1.

不過如果你將第2行代碼注釋掉。代碼就能跑通了,如圖-2。

問題1來了:TestVariableScope.a 不是也沒有被定義嗎,為什么可以work呢?解釋如下:先看代碼第8行,TestVariableScope.a在SetVariable方法中被定義了,SetVariable()又 在TestVariableScope()前被調用。所以TestVariableScope()在被調用的時候TestVariableScope.a已經被定義了。

問題2來了:代碼第7行,a也被定義了。為什么TestVariableScope()在引用a是報錯呢。區別在於:a 只是SetVariable()中的一個local變量,TestVariableScope當然無法引用SetVariable中定義的局部變量了。因為違反了LEGB原則嗎。TestVariableScope.a 就不一樣了,他是一個全局變量哦。所以TestVariableScope當然可以訪問這個全局變量了,完全不違反LEGB原則。

問題3來了:為什么TestVariableScope.a是個全局變量,而a卻不是呢。因為python中函數皆是對象,而且是全局對象。TestVariableScope.a其實就是TestVariableScope這個全局對象下的一個變量而已,自然也是全局變量嘍。 見圖-3

 

 1 def TestVariableScope():
 2     print(a)
 3     print(TestVariableScope.a)
 4     TestVariableScope.a=13
 5 
 6 def SetVariable():
 7     a=12
 8     TestVariableScope.a=12
 9 
10 if __name__=='Demo':
11     print('Demo is running')
12 
13 if __name__ == '__main__':
14     SetVariable()
15     TestVariableScope()
16     b=TestVariableScope
17     b()

圖-1

圖-2

圖-3

 

以下關於LEGB, 引用自:https://magicalboy.com/python-scope-legb 

Python 的變量作用域和 LEGB 原則

在 Python 程序中創建、改變或查找變量名時,都是在一個保存變量名的地方進行中,那個地方我們稱之為命名空間。作用域這個術語也稱之為命名空間。

具體地說,在代碼中變量名被賦值(Python 中變量聲明即賦值,global 聲明的只是變量的使用域)的位置決定了該變量能被訪問的范圍。函數定義了本地作用域,而模塊定義的是全局作用域。這兩個作用域之前有如下關系:

  • 每一個模塊都是全局作用域。也就是說,創建於模塊文件頂層的變量具有全局作用域,對於外部訪問就成了一個模塊對象的屬性。
  • 全局作用域的作用范圍僅限於單個文件。“全局”指的是在一個文件的頂層變量名對於這個文件而言是全局的。
  • 每次對函數的調用都創建了一個新的本地作用域。Python 中也有遞歸,即可以調用自身,每次調用都會創建五個新的本地命名空間。
  • 賦值的變量名除非聲明為全局變量,否則均為本地變量。如果需要在函數內部對模塊文件頂層的變量名賦值,需要在函數內部通過 global 語句聲明該變量。
  • 所有的變量可歸納為本地、全局或者內置三種。范圍分別為 def 內部,在一個模塊的命名空間內部和預定義的 __builtin__ 模塊提供的變量。

變量名解析:LEGB 原則

如果對以上內容有所迷惑的話,請看以下總結出的幾條原則。在函數命名空間中:

  • 變量名引用分為三個作用域進行查找:首先是本地,然后是函數內(如果有的話),之后是全局,最后是內置。
  • 在默認情況下,變量名賦值會創建或者改變本地變量。
  • 全局聲明將會給映射到模塊文件內部的作用域的變量名賦值。
  • Python 的變量名解析機制也稱為 LEGB 法則,具體如下: 當在函數中使用未確定的變量名時,Python 搜索 4 個作用域:本地作用域(L),之后是上一層嵌套結構中 def 或 lambda 的本地作用域(E),之后是全局作用域(G),最后是內置作用域(B)。按這個查找原則,在第一處找到的地方停止。如果沒有找到,Python 會報錯的。
  • 下圖說明了搜索流程(由內及外):


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM