Python中LEGB規則 變量查找順序Local/Enclosing/Global/Builtin詳解

python中變量的查找順序是legb規則。具體來說,1. local:函數內部定義的變量優先被使用,若未賦值前引用會報錯;2. enclosing:嵌套函數外層作用域變量可訪問,修改需用nonlocal;3. global:模塊層級的全局變量,跨模塊不可見;4. builtin:內置作用域,包含內置函數和變量,避免覆蓋。合理使用作用域和聲明關鍵字能有效避免錯誤。

python中,變量的查找順序是按照LEGB規則來執行的。簡單來說,就是當你在代碼中使用一個變量時,Python會按照 Local → Enclosing → Global → Builtin 這個順序去查找這個變量的值。

這聽起來好像挺簡單的,但實際寫代碼的時候,特別是函數嵌套、模塊導入混在一起時,很容易出錯。下面我們就從幾個常見的場景出發,看看LEGB到底是怎么起作用的。


Local:局部作用域優先

Local指的就是函數內部定義的作用域。只要你在一個函數里面用 = 給變量賦值(除非特別說明是global或nonlocal),它就會被認為是局部變量

舉個例子:

立即學習Python免費學習筆記(深入)”;

def func():     x = 10     print(x)  func()

這里打印的是10,沒問題。但如果你這樣寫:

def func():     print(x)     x = 10  func()

這時候就會報錯:UnboundLocalError: local variable ‘x’ referenced before assignment。

因為Python看到你在函數里給x賦值了,所以它認定x是一個局部變量。但在print的時候還沒賦值,就出錯了。

建議:

  • 如果你想在函數里使用全局變量,記得加 global 聲明。
  • 如果你在嵌套函數里想修改外層函數的變量,要用 nonlocal。

Enclosing:嵌套函數的外層作用域

Enclosing指的是嵌套函數的外層函數的作用域。這是很多新手容易忽略的地方。

比如:

def outer():     x = "outer"      def inner():         print(x)      inner()  outer()

這里inner函數能訪問到outer里的x,這就是Enclosing作用域在起作用。

但如果我們在inner里試圖修改x呢?

def outer():     x = "outer"      def inner():         x = "inner"         print(x)      inner()     print(x)  outer()

結果會是:

inner outer

說明inner里的x是它自己的局部變量,并沒有影響到outer里的x。

如果你希望inner修改outer中的x,就要加上 nonlocal:

def outer():     x = "outer"      def inner():         nonlocal x         x = "inner"         print(x)      inner()     print(x)  outer()

輸出:

inner inner

Global:模塊層級的全局變量

Global指的是在模塊層級(也就是不在任何函數里)定義的變量。

比如:

x = "global"  def func():     print(x)  func()

這時打印的是 “global”,因為func找不到局部變量x,就去全局找。

但如果你在func里重新賦值x,又不加global,那又會觸發前面說的那個錯誤。

常見誤區:

  • 模塊A導入了模塊B,模塊B中的函數不能直接訪問模塊A的全局變量。
  • 全局變量不是“整個程序”的變量,而是當前模塊下的。

Builtin:內置作用域

Builtin是最底層的作用域,包含了Python自帶的一些內置函數和變量,比如 print()、len()、True、Exception 等。

你可以把它理解為“最后兜底”的一層。

比如你寫:

print(len("hello"))

這里的 len 就是從Builtin作用域里找到的。

但如果你不小心覆蓋了內置變量,可能會出問題:

len = "oops" print(len("hello"))  # 報錯:TypeError: 'str' object is not callable

這時候你就把內置的 len 函數覆蓋成了字符串,當然就不能用了。

建議:

  • 不要隨便用內置名稱做變量名。
  • 可以用 del len 來恢復,但這只是臨時解決辦法,最好一開始就避免。

基本上就這些。LEGB規則雖然看起來簡單,但在函數嵌套、變量遮蔽等情況下容易讓人掉坑。平時寫代碼時注意變量作用域,合理使用 global 和 nonlocal,就能避免很多莫名其妙的問題。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享