1. 程式人生 > 其它 >學習python,從入門到放棄(12)

學習python,從入門到放棄(12)

學習python,從入門到放棄(12)

名稱空間

其實就是存放變數名與變數值繫結關係的地方,大體可分為三類:內建名稱空間、全域性名稱空間、區域性名稱空間。

  • 內建名稱空間

    屬於python直譯器提前給我們定義好的,像 len() pring() open() 等都是內建名稱空間。程式任意階段任意位置均可使用(全域性有效)。

    隨著 python 直譯器執行而產生,隨著 python 直譯器關閉而銷燬。

  • 全域性名稱空間

    在 py 檔案中編寫的程式碼,執行後產生的變數名、函式名等都會存到全域性名稱空間中。

    name = 'jason'  # 變數名name存入全域性名稱空間
    def index():  # 函式名index存入全域性名稱空間
        pass
    if True:
        a = 111  # 變數名a存入全域性名稱空間
    for i in range(10):  # 變數名i存入全域性名稱空間
        pass
    while True:
        b = 222  # 變數名b存入全域性名稱空間
    

    隨著 py 檔案開始執行而產生,隨著 py 檔案執行結束而銷燬。程式任意階段任意位置均可使用(全域性有效)。

  • 區域性名稱空間

    函式體程式碼執行產生的都是區域性名稱空間

    def index():
          name = 'jason'  # name存入區域性名稱空間
    

    隨著函式體程式碼開始執行而產生,隨著函式體程式碼執行結束而銷燬。一般情況下只在各自區域性名稱空間中有效(區域性有效)

名字的查詢順序

名稱空間是用來存放名字與值繫結關係的地方,當一行程式碼要使用變數 x 的值時,Python會到所有可用的名稱空間去查詢變數,按照如下順序:

  1. 區域性名稱空間 - 特指當前函式或類的方法。如果函式定義了一個區域性變數 x,Python 將使用這個變數,然後停止搜尋。
  2. 全域性名稱空間 - 特指當前的模組。如果模組定義了一個名為 x 的變數,函式或類,Python 將使用這個變數然後停止搜尋。
  3. 內建名稱空間 - 對每個模組都是全域性的。作為最後的嘗試,Python 將假設 x 是內建函式或變數。
  4. 如果 Python 在這些名稱空間找不到 x,它將放棄查詢並引發一個 NameError 的異常,同時傳 遞 There is no variable named 'x' 這樣一條資訊。

global 與 nonlocal 關鍵字

  • global 關鍵字

    根據 Python 訪問區域性變數和全域性變數的規則:當搜尋一個變數的時候,Python 先從區域性作用域開始搜尋,如果在區域性作用域沒有找到那個變數,那樣 Python 就會像上面的介紹的那樣逐層尋找。最終在全域性變數中找這個變數,如果找不到則丟擲異常。

    但有時候會出現,明明已經在全域性變數中找到同名變量了,還是報錯的情況。

    因為內部函式有引用外部函式的同名變數或者全域性變數,並且對這個變數有修改的時候,此時 Python 會認為它是一個區域性變數,而函式中並沒有 x 的定義和賦值,所以報錯。

    global 關鍵字為解決此問題而生。

    x = 111
    
    
    def a():
        print(x)
    
    
    def b():
        global x
        x +=1
        print(x)
    
    
    a()  # 111
    b()  # 112
    

    在函式 b 中,顯示地告訴直譯器 x 為全域性變數,然後會在函式外面尋找 x 的定義,執行完 x = x + 1 後,x 依然是全域性變數。

  • nonlocal 關鍵字

    nonlocal 關鍵字和 global 關鍵字的作用類似。

    但只能用於函式巢狀的情況,也就是函式套函式的情況。

    x = 111
    
    
    def a():
        x = 222
    
        def b():
            nonlocal x
            print(x)  # 222
            x = 333
    
        b()
        print(x)  # 333
    
    
    a()
    print(x)  # 111
    

    可以從內層修改外層。

函式名的多種用法

  • 函式名當變數名賦值

    def index():
        print('from function index')
    
    
    print(index)  # <function index at 0x0000013E6BB11EA0>
    res = index  # 讓res也指向函式體程式碼
    print(res)  # <function index at 0x0000013E6BB11EA0>
    index()  # from function index
    res()  # from function index
    
  • 函式名當函式的實參

    def index():
        print('from index')
    def func(a):
        print('from func')
        print(a)  # <function index at 0x000001786E6F1EA0>
        a()  # from index
    func(index)
    print(index)  # <function index at 0x000001786E6F1EA0>
    
  • 函式名當函式的返回值

    def func():
        print('from func')
        return index  # 將函式名當做返回值
    
    
    def index():
        print('from index')
    
    
    res = func()  # res接收函式名
    print(res)  # 指向的是index函式的記憶體地址
    res()  # index()
    
  • 函式名作為容器型別的元素

    def index():
        print('from index')
    
    
    l1 = [11, 22, 33, 44, index]
    print(l1)
    l1[-1]()  # index()
    

函式的巢狀

所謂在Python函式中定義巢狀函式,就是說在函式中再定義函式,或者說,把一個函式定義在另一個函式的內部。這是Python語言獨有的一個特點。

函式的巢狀定義,帶來一個好處,就是可以實現用函式去封裝函式。比如有一個函式A,這個A函式在執行過程中,需要呼叫BCDE等好幾個其它的函式,如果BCDE等這些其它的函式,只有A在呼叫,我們就完全可以將BCDE等函式的定義,寫入A函式的內部。這種就封裝了BCED等函式,程式碼看起來更加優雅簡潔!

將BCDE等函式巢狀寫入A函式的內部,還有一個好處,BCDE等函式可以直接訪問A函式區域性空間中的變數。如果BCDE等函式沒有巢狀定義到A函式內部,A在呼叫它們的時候,可能就要傳遞更多的引數給BCDE等函式,BCDE等函式的返回值可能也會變複雜,甚至還可能會增加全域性變數來為他們的互動提供協助。

總結

今天的知識都是偏理論,需要仔細推敲,反覆琢磨,讀懂之後對以後寫程式碼的幫助很大。