Python 變數範圍

來源:互聯網
上載者:User

標籤:活動   var   if語句   變數賦值   not   UNC   綁定   int()   ***   

Python 變數範圍

變數範圍LEGB
1、變數的範圍
在Python程式中建立、改變或尋找變數名時,都是在一個儲存變數名的空間(命名空間)中進行的,我們稱這個命名空間為範圍。Python的範圍是靜態,在原始碼中變數名被賦值的位置決定了該變數能被訪問的範圍,即Python變數的範圍由變數所在原始碼中的位置決定。

2、進階語言對資料類型的使用過程
一般的進階語言在使用變數時,都會有下面4個過程,當然不同的語言也會有著區別:

  • 1.聲明變數:讓編譯器知道由這個變數的存在;
  • 2.定義變數:為不同資料類型的變數分配記憶體空間;
  • 3.初始化:賦值,填充分配好的記憶體空間;
  • 4.引用:通過引用對象(變數名)來調用記憶體對象(記憶體資料);

3、範圍的產生
就範圍而言,Python與C有著很大的區別,在Python中並不是所有的語句塊都會產生範圍。只有當變數在Module(模組)、Class(類)、def(函數)中定義的時候,才會有範圍的概念。如下代碼:

def func():    variable = 100    print(variable)print(variables)        # NameError: name ‘variables‘ is not defined,在pycharm中就會自動報錯

在範圍中定義的變數,一般只在範圍中有效。需要注意的是:在if-elif-else、for-else、while、try-except/try-finally等關鍵字的語句塊中並不會產生範圍,如下代碼:

if True:    variable = 100    print(variable)     # 100print("*"*12)       # ************print(variable)     # 100

所以,可以看到,雖然在if語句中定義的variable變數,但是在if語句外仍然能夠使用。

4、範圍的類型:
在Python中,使用一個變數時並不嚴格要求預先聲明它,但是在真正使用它之前,他必須被綁定到某個記憶體對象(被定義、賦值);這種變數名的綁定將在當前範圍中引入新的變數,同事屏蔽外層範圍中的同名變數。
L(local)局部變數範圍
局部變數:包含在def關鍵字定義的語句塊中,即在函數中定義的變數。每當函數被調用時都會建立一個新的局部範圍。Python中也有遞迴,即自己調用自己,每次調用都會建立一個新的局部命名空間。在函數內部的變數聲明,除非特別的聲明為全域變數,否則均預設為局部變數。有些情況需要在函數內部定義全域變數,這時可以使用global關鍵字來聲明變數的範圍為全域。局部變數域就像一個棧,僅僅是暫時的存在,依賴建立該局部範圍的函數是否處於活動的狀態。所以,一般建議盡量少用全域變數,因為全域變數在模組檔案啟動並執行過程中會一直存在,佔用記憶體空間。
注意:如果需要在函數內部對全域變數賦值,需要在函數內部通過global語句聲明該變數為全域變數。

E(enclosing)嵌套範圍
E也包含在def關鍵字中,E和L是相對的,E相對於更上層的函數而言也是L。與L的區別在於,對一個函數而言,L是定義在此函數內部的局部範圍,而E是定義在此函數的上一層父級函數的局部範圍,主要是為了實現Python的閉包,而增加的實現。

G(global)全域範圍
即在模組層次中定義的變數,每一個模組都是一個全域範圍。也就是說,在模組檔案頂層聲明的變數具有全域範圍,從外部來看,模組的全域變數就是一個模組對象的屬性。
注意:全域範圍的作用範圍僅限於單個模組檔案內。

B(built-in)內建範圍
系統內固定模組裡定義的變數,如與定義在builtin模組內的變數。

5、變數名解析LEGB法則
搜尋變數名的優先順序:局部範圍-> 嵌套範圍-> 全域範圍-> 內建範圍
LEGB法則:當在函數中使用未確定的變數名時,Python會按照優先順序依次搜尋4個範圍,以此來確定該變數名的意義。首先搜尋局部範圍(L),之後是上一層嵌套結構中def或lambda函數的嵌套範圍(E),之後是全域範圍(G),最後是內建範圍(B)。按照這個尋找原則,在第一處找到的地方停止,如果沒找到,則會拋出NameError異常。如下執行個體:

def func():    variable = 300    print(variable)     # 300variable = 100func()print(variable)     # 100
variable = 100def test_scope():    print(variable)     # variable是test_scope()的局部變數,但是在列印時並沒有綁定記憶體對象,所以在pycharm中就會報錯    variable = 200test_scope()print(variable)

上面的例子會產生錯誤,因為在執行程式的時的先行編譯能夠在test_scope()中找到局部變數variable(對variable進行了賦值)。在局部範圍找到了變數名,所以不會升級到嵌套範圍去尋找,但是在使用print()將變數variable列印時,局部變數並沒有綁定到一個記憶體對象(沒有定義和初始化,即沒有賦值)。本質上還是Python調用變數時遵循的LEGB法則和Python解譯器的編譯原理,決定了這個錯誤的發生。所以,在調用一個變數之前,需要為該變數賦值(綁定一個記憶體對象)。
注意:為什麼在這個例子中觸發的錯誤是"UnboundLocalError: local variable ‘variable‘ referenced before assignment",而不是"NameError:name ‘variable’ is not defined"。這是因為變數variable不是在全域範圍。Python中的模組代碼在執行前,並不會經過先行編譯,但是模組內的函數體代碼在運行前會經過先行編譯,因此不管變數名的綁定發生在範圍的哪個位置,都能被編譯器知道。Python雖然是一個靜態範圍語言,但變數名尋找是動態發生的,直到在程式運行時,才會發現範圍方面的問題。

Python 變數範圍

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.