在Python中,對象是經過名字進行關聯和引用的。Python經過名字綁定操做來引入名字。html
Python中的所謂的代碼塊就是一段做爲執行單元的程序。好比:模塊、函數、類定義。在交互式環境中輸入的命令也是代碼塊的一種。一個Python腳本文件也是一個代碼塊。還有就是,當咱們在命令行上使用-c
選項指定的命令也是一個代碼塊。傳遞給內建函數eval()和exec()的字符串參數也是代碼塊的一種。python
代碼塊是以執行幀的方式被執行的,一個執行幀包含了一些管理信息,能夠用於調試。執行幀還會在執行完當前的代碼塊之後指定在何處,以怎樣的方式執行接下來的代碼。shell
Python中的做用域定義了名字在代碼塊中的可見性。若是在代碼塊中定義了一個局部變量,那麼這個局部變量的做用域就是所在的這個代碼塊。若是這個定義發生在函數體內,則這個變量的做用域就擴展到包含在這個函數中的任何代碼塊中,可是,若是包含在這個函數中的一個代碼塊中,一樣的名字被綁定到了不一樣的對象上,那麼外面的名字將不能被擴展到這個代碼塊中。函數
def out_func(): #a的做用域在out_func這個函數中 a = 0 b = 0 def in_func(): #a的做用域從out_func擴展到了in_func中,由於in_func這個代碼塊包含在out_func中 print(a) #out_func函數中的b不能擴展到in_func中,由於在in_func中,b從新綁定到了不一樣的對象上,因此在out_func中的b的做用域不能擴展到in_func中。 b = 1
在Python中,定義在類代碼塊中名字只能在類中可見,而且類中的名字的做用域不能擴展到類中的方法中。若是在類定義中出現了生成器表達式和列表展開,那麼類中的名字也不能擴展到這些表達式中,由於列表展開和生成器表達式的實現都是使用函數做用域的。ui
class C: a = 0 # 在列表表達式中,a會由於未定義而拋出NameError異常 b = list(a + i for i in range(10)) def method(self): #因爲定義在類中的名字不能擴展到方法中,因此下面的語句是錯誤的,會拋出a未定義的NameError異常 print(a)
當在一個代碼塊中使用一個名字的時候,會對最近的外圍做用域進行解析,以查找這個名字。全部的這些在當前代碼塊中可見的做用域的集合,稱爲
當前的代碼塊的環境。命令行
若是一個名字綁定到一個代碼塊中,除非這個名字聲明爲nonlocal(nonlocal聲明的做用是:使得變量在外圍做用域中,在全局做用域以前被解析),不然這個名字就是這個代碼塊的局部變量。若是一個名字被綁定到模塊級別,則這個名字的做用域是全局的,這個變量是全局變量(模塊中的變量,對於模塊而言是局部變量,而對於模塊中的代碼塊而言,則是全局變量)。若是一個名字在一個代碼塊中使用,可是不是在這個代碼塊中被定義的,則這個變量就是一個自由變量。調試
若是在進行名字查找的時候,名字沒有被找到,則會拋出一個 NameError 異常,若是名字引用的是一個局部變量,可是這個名字尚未被綁定到這個局部變量,則會拋出一個 UnboundLocalError 異常(UnboundLocalError 是 NameError的子類)。code
發生名字綁定的行爲主要有:htm
from ... import *
語句會將被導入的模塊中的全部能夠被導入的名字進行綁定操做在Python中,名字綁定的一些規則,會致使在使用名字的時候,出現不能理解的錯誤,特別是對於有C、C++ 和 Java經驗的用戶。對象
在Python中,名字綁定操做不管發生在當前塊的 任何 位置,在這個代碼塊中對這個名字的引用都會使用在當前塊中綁定的對象。那麼,問題就來了,若是咱們在名字綁定操做發生以前對這個名字進行了引用,那麼就會出現錯誤,拋出 UnboundLocalError 異常。
>>> a = 10 >>> def function(): print(a) a = 20 # a的綁定操做發生在print以前 >>> function() Traceback (most recent call last): File "<pyshell#5>", line 1, in <module> function() File "<pyshell#4>", line 2, in function print(a) UnboundLocalError: local variable 'a' referenced before assignment
在Python中,代碼塊中的局部變量能夠經過掃描整個代碼塊來得到綁定的名字,因此在上面的代碼中,a這個名字在執行print的時候經過對代碼塊的掃描已經被找到,可是名字a的綁定操做卻尚未發生,因此出現了錯誤。
在上面的代碼中,若是咱們須要外面定義的全局變量a,則可使用global 語句進行聲明。
>>> a = 10 >>> def function(): global a print(a) a = 20 #這裏並不引入新的名字,而是將全局變量a綁定到20上 >>> function() 10 >>> a 20
global 語句的做用是,使得後面對經過這條語句聲明的對象的引用,使用的是頂層名字空間中的名字。在頂層名字空間中,包含了全局名字空間和內建名字空間,全局名字空間會首先被搜索,若是沒有找到,會對內建名字空間進行搜索。global 語句必須出如今名字使用以前。
若是在外圍做用域中的自由變量包含了一個global聲明,則這個自由變量被認爲是全局的。
在查找內建名字空間的時候,會訪問當前代碼塊的全局名字空間中的 __builtins__名字,這個名字引用的是一個名字字典或者是一個模塊。在 __main__ 模塊中, __builtins__ 的引用是內建模塊 builtins,然而,若是是在其餘模塊中, __builtins__ 引用的是 builtins 模塊的名字字典。
注意:
CPython的實現中,不能手動修改 __builtins__ 這個變量,若是須要覆蓋這個內建名字空間中的名字,須要導入 builtins 模塊,而後修改這個模塊中相應的屬性。