1. 程式人生 > 程式設計 >Python作用域與名字空間原理詳解

Python作用域與名字空間原理詳解

Python具有靜態作用域,變數的作用域由它定義的位置決定,而與呼叫的位置無關。

a = 2
def f():
a = 2

第一行的a的作用域是全域性作用域,作用於定義位置後面的所有位置。

第四行的a的作用域是區域性作用域,作用於f函式裡。

Python能夠形成區域性作用域的只有函式與類,其他語句不形成區域性作用域。

函式與類的區域性作用域

def f():
  a = 1
class A:
  b = 2
if 1 == 1:
  c = 3
for _ in range(1):
  d = 4
while True:
  e = 5
  break
print(c,d,e)
try:
  print(a)
except Exception as e:
  print(e)
try:
  print(b)
except Exception as e:
  print(e)

輸出結果

3 4 5
name 'a' is not defined
name 'b' is not defined

python動態執行時,每個作用域都有三個名字空間:由區域性變數組成的local名字空間,由全域性變數組成的global名字空間,以及python內建模組的builtins名字空間,在查詢一個變數時,搜尋順序為local->global->builtins,即區域性變數遮蔽全域性變數,全域性變數遮蔽內建變數。

python的global名字空間是動態的,即每遇到一個賦值語句(def與class也屬於賦值語句),global名字空間都可能發生變化。

global名字空間的動態變化

print(dir())
a = 1
print(dir())
b = 2
print(dir())

輸出結果

1 ['__annotations__','__builtins__','__cached__','__doc__','__file__','__loader__','__name__','__package__','__spec__']
2 ['__annotations__','__spec__','a']
3 ['__annotations__','a','b']

從輸出結果可以看出,global名字空間是動態增加的。

這意味著,雖然位於global名字空間的變數叫做全域性變數,它的作用範圍也不是全域性位置,它只作用於第一次賦值之後的位置。因為只有在變數賦值初始化的時候,它才會被加入到global名字空間中。

函式和類搜尋的global名字空間是呼叫位置的global名字空間,與定義位置無關

def f():
  print(a)

try:
  f()
except Exception as e:
  print(e)

a = 2
f()

輸出結果

name 'a' is not defined
2

函式f列印全域性變數a,a在第9行定義。在第五行呼叫f的時候,a不在global名字空間中,所以會輸出錯誤資訊,在第十行再次呼叫函式f時,a已經加入了global名字空間,所以能夠打印出a。

python為了提高效率,local名字空間是靜態實現的,因為對於一個函式來說,它所包含的區域性變數是明確已知的。

函式的local名字空間是靜態的

a = 4
def f():
  try:
    print(a)
  except Exception as e:
    print(e)
  a = 1
f()

輸出結果

local variable 'a' referenced before assignment

在列印a的時候,在local名字空間中找到了a,但是這時候a並沒有賦值初始化,所以丟擲異常。這也說明了local名字空間與global名字空間不同,它會在一開始就把所有的區域性變數加入到名字空間中。

總結:

1. python是靜態作用域,變數初始化的位置決定了它的作用域,而與變數呼叫的位置無關

2. global名字空間是動態的,不同位置的global名字空間不同,local名字空間是靜態的,區域性變數在整個區域性作用域內可見。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。