Python的名字綁定

來源:互聯網
上載者:User
Python的名字綁定

在Python中,對象是通過名字進行關聯和引用的。Python通過名字綁定操作來引入名字。

Python中的所謂的代碼塊就是一段作為執行單元的程式。比如:模組、函數、類定義。在互動式環境中輸入的命令也是代碼塊的一種。一個Python指令檔也是一個代碼塊。還有就是,當我們在命令列上使用-c選項指定的命令也是一個代碼塊。傳遞給內建函數eval()和exec()的字串參數也是代碼塊的一種。

代碼塊是以執行幀的方式被執行的,一個執行幀包含了一些管理資訊,可以用於調試。執行幀還會在執行完當前的代碼塊以後指定在何處,以怎樣的方式執行接下來的代碼。

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中,定義在類代碼塊中名字只能在類中可見,並且類中的名字的範圍不能擴充到類中的方法中。如果在類定義中出現了產生器運算式和列表展開,那麼類中的名字也不能擴充到這些運算式中,因為列表展開和產生器運算式的實現都是使用函數範圍的。

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的子類)。

發生名字綁定行為的情況

發生名字綁定的行為主要有:

通常的給函數傳遞參數的時候,參數名會和傳遞過來的對象進行綁定

使用import語句進行匯入的時候,其中 from ... import * 語句會將被匯入的模組中的所有可以被匯入的名字進行綁定操作

類定義的時候

函數定義的時候

進行賦值操作的時候

在for迴圈的for語句中

在with語句中的as後面

在expect語句中的as後面

Python中的名字綁定的Pitfall

在Python中,名字綁定的一些規則,會導致在使用名字的時候,出現不能理解的錯誤,特別是對於有C、C++ 和 Java經驗的使用者。

在Python中,名字綁定操作無論發生在當前塊的 任何 位置,在這個代碼塊中對這個名字的引用都會使用在當前塊中綁定的對象。那麼,問題就來了,如果我們在名字綁定操作發生之前對這個名字進行了引用,那麼就會出現錯誤,拋出 UnboundLocalError 異常。

>>> a = 10>>> def function():print(a)a = 20# a的綁定操作發生在print之前>>> function()Traceback (most recent call last):  File "", line 1, in     function()  File "", line 2, in function    print(a)UnboundLocalError: local variable 'a' referenced before assignment

在Python中,代碼塊中的局部變數可以通過掃描整個代碼塊來獲得綁定的名字,所以在上面的代碼中,a這個名字在執行print的時候通過對代碼塊的掃描已經被找到,但是名字a的綁定操作卻還沒有發生,所以出現了錯誤。

在上面的代碼中,如果我們需要外面定義的全域變數a,則可以使用global 語句進行聲明。

>>> a = 10>>> def function():global aprint(a)a = 20#這裡並不引入新的名字,而是將全域變數a綁定到20上>>> function()10>>> a20

global 語句的作用是,使得後面對通過這條語句聲明的對象的引用,使用的是頂層名字空間中的名字。在頂層名字空間中,包含了全域名字空間和內建名字空間,全域名字空間會首先被搜尋,如果沒有找到,會對內建名字空間進行搜尋。global 語句必須出現在名字使用之前。

如果在外圍範圍中的自由變數包含了一個global聲明,則這個自由變數被認為是全域的。

內建名字空間

在尋找內建名字空間的時候,會訪問當前代碼塊的全域名字空間中的 __builtins__名字,這個名字引用的是一個名字字典或者是一個模組。在 __main__ 模組中, __builtins__ 的引用是內建模組 builtins,然而,如果是在其他模組中, __builtins__ 引用的是 builtins 模組的名字字典。

注意:

CPython的實現中,不能手動修改 __builtins__ 這個變數,如果需要覆蓋這個內建名字空間中的名字,需要匯入 builtins 模組,然後修改這個模組中相應的屬性。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.