1. 程式人生 > 實用技巧 >python-作用域

python-作用域

  • 名稱空間

名稱空間(Namespace)是從名稱到物件的對映,大部分的名稱空間都是通過 Python 字典來實現的

名稱空間提供了在專案中避免名字衝突的一種方法

各個名稱空間是獨立的,沒有任何關係的,所以一個名稱空間中不能有重名,但不同的名稱空間是可以重名而沒有任何影響

包括內建名稱(built-in names,python本身定義的名稱),全域性名稱(global names,模組中定義的名稱),區域性名稱(local names,函式中定義的名稱)

如果要使用變數 runoob,則 Python 的查詢順序為:區域性的名稱空間去 -> 全域性名稱空間 -> 內建名稱空間

如果找不到變數 runoob,它將放棄查詢並引發一個 NameError 異常

# var1 是全域性名稱
var1 = 5
def some_func():
 
    # var2 是區域性名稱
    var2 = 6
    def some_inner_func():
 
        # var3 是內嵌的區域性名稱
        var3 = 7

名稱空間的生命週期取決於物件的作用域,如果物件執行完成,則該名稱空間的生命週期就結束。

因此,我們無法從外部名稱空間訪問內部名稱空間的物件。

  • 作用域

L(Local):最內層,包含區域性變數,比如一個函式/方法內部

E(Enclosing):包含了非區域性(non-local)也非全域性(non-global)的變數。比如兩個巢狀函式,一個函式(或類) A 裡面又包含了一個函式 B ,那麼對於 B 中的名稱來說 A 中的作用域就為 nonlocal

G(Global):當前指令碼的最外層,比如當前模組的全域性變數

B(Built-in): 包含了內建的變數/關鍵字等,最後被搜尋

Python 中只有模組(module),類(class)以及函式(def、lambda)才會引入新的作用域(其內的變數為區域性變數,外部無法呼叫,使用的時候是通過傳參的方式)

其它的程式碼塊(如 if/elif/else/、try/except、for/while等)是不會引入新的作用域的,也就是說這些語句內定義的變數,外部也可以訪問

total = 0 # 這是一個全域性變數
# 可寫函式說明
def sum( arg1, arg2 ):
    #返回2個引數的和."
    total = arg1 + arg2 # total在這裡是區域性變數.
    print ("函式內是區域性變數 : ", total)
    return total
#呼叫sum函式
sum( 10, 20 )
print ("函式外是全域性變數 : ", total)
# 函式內是區域性變數 :  30
# 函式外是全域性變數 :  0

函式內的區域性變數和函式外的全域性變數互不干擾,並且只能在各自所屬的區域內呼叫

當內部作用域想修改外部作用域的變數時,就要用到global和nonlocal關鍵字了

num = 1
def fun1():
    global num  # 需要使用 global 關鍵字宣告
    print(num) 
    num = 123
    print(num)
fun1()
print(num)
# 1
# 123
# 123

在函式的開頭使用global表明使用的是全域性num變數,後續的檢視和操作都是針對於這個全域性變數(此處沒有建立新的變數)

def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal關鍵字宣告
        num = 100
        print(num)
    inner()
    print(num)
outer()
# 100
# 100

使用nonlocal表明使用的是外層巢狀函式的變數

a = 10
def test():
    global a
    a = a + 1
    print(a)
test()
# 11

如果不設定global,則會出現函式內a為定義的錯誤

a = 10
def test(a):
    a = a + 1
    print(a)
test(a)
# 11

也可以使用傳遞的引數