Python學習之變量的做用域

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

一、變量做用域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等關鍵字的語句塊中並不會產成做用域。看下面的代碼:ui

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

代碼的輸出爲:spa

100
******
100

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

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雖然是一個靜態做用域語言,但變量名查找是動態發生的,直到在程序運行時,纔會發現做用域方面的問題
相關文章
相關標籤/搜索