1. 程式人生 > >Python學習之變量的作用域

Python學習之變量的作用域

運行 python變量 存在 變量 語言 相對 沒有 情況 變量賦值

學習地址:http://www.jianshu.com/p/17a9d8584530

1、變量作用域LEGB

1.1變量的作用域

在Python程序中創建、改變、查找變量名時,都是在一個保存變量名的空間中進行,我們稱之為命名空間,也被稱之為作用域。python的作用域是靜態的,在源代碼中變量名被賦值的位置決定了該變量能被訪問的範圍。即Python變量的作用域由變量所在源代碼中的位置決定。

1.2高級語言對數據類型的使用過程

一般的高級語言在使用變量時,都會有下面4個過程。當然在不同的語言中也會有著區別。

  1. 聲明變量:讓編輯器知道有這一個變量的存在
  2. 定義變量:為不同數據類型的變量分配內存空間
  3. 初始化:賦值,填充分配好的內存空間
  4. 引用:通過引用對象(變量名)來調用內存對象(內存數據)

1.3作用域的產生

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

#!/usr/bin/env python
def func():
    variable = 100
    print variable
print variable

代碼的輸出為:

NameError: name ‘variable‘ is not defined

在作用域中定義的變量,一般只在作用域中有效。 需要註意的是:在if-elif-else、for-else、while、try-except\try-finally等關鍵字的語句塊中並不會產成作用域。看下面的代碼:

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

代碼的輸出為:

100
******
100

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

1.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 模塊內的變量。

1.5變量名解析LEGB法則

搜索變量名的優先級:局部作用域 > 嵌套作用域 > 全局作用域 > 內置作用域
LEGB法則: 當在函數中使用未確定的變量名時,Python會按照優先級依次搜索4個作用域,以此來確定該變量名的意義。首先搜索局部作用域(L),之後是上一層嵌套結構中def或lambda函數的嵌套作用域(E),之後是全局作用域(G),最後是內置作用域(B)。按這個查找原則,在第一處找到的地方停止。如果沒有找到,則會出發NameError錯誤。

幾個實例:

1.

def func():
    variable = 300
    print variable

variable = 100
func() #300
print variable  #100

2.

variable = 300 def test_scopt():   print variable #variable是test_scopt()的局部變量,但是在打印時並沒有綁定內存對象。   variable = 200 #因為這裏,所以variable就變為了局部變量 test_scopt() print variable 上面的例子會報出錯誤,因為在執行程序時的預編譯能夠在test_scopt()中找到局部變量variable(對variable進行了賦值)。在局部作用域找到了變量名,所以不會升級到嵌套作用域去尋找。但是在使用print語句將變量variable打印時,局部變量variable並有沒綁定到一個內存對象(沒有定義和初始化,即沒有賦值)。本質上還是Python調用變量時遵循的LEGB法則和Python解析器的編譯原理,決定了這個錯誤的發生。所以,在調用一個變量之前,需要為該變量賦值(綁定一個內存對象)。
註意:為什麽在這個例子中觸發的錯誤是UnboundLocalError而不是NameError:name ‘variable’ is not defined。因為變量variable不在全局作用域。Python中的模塊代碼在執行之前,並不會經過預編譯,但是模塊內的函數體代碼在運行前會經過預編譯,因此不管變量名的綁定發生在作用域的那個位置,都能被編譯器知道。Python雖然是一個靜態作用域語言,但變量名查找是動態發生的,直到在程序運行時,才會發現作用域方面的問題





 

 
 

 


Python學習之變量的作用域