编程Python开发者

什么是Python中的'LEGB规则'?它在查找变量名称时如何工作?请举例说明对该规则的错误理解如何导致复杂的错误。

用 Hintsage AI 助手通过面试

答案。

LEGB规则是Python中命名空间(作用域)查找的规则。缩写代表着:

  • Local — 局部命名空间(在函数内部);
  • Enclosing — 所有嵌套函数的命名空间;
  • Global — 模块命名空间(全局变量);
  • Builtin — Python中的内置名称(lenlist等)。

当Python遇到一个变量时,它首先在局部查找,然后在嵌套函数中查找,接下来在模块的全局范围内查找,最后在内置对象的命名空间中查找:

def outer(): x = 'enclosing' def inner(): x = 'local' print(x) inner() outer() # 'local'

如果在inner()内部去掉对x的赋值,Python会从外部作用域(outer)中获取x。如果那里也没有变量,就会查找全局变量,然后是内置的。


诱导性问题。

如果在修改外层作用域的变量时忘记声明nonlocalglobal,函数的行为会有什么变化?

回答: 如果试图在嵌套函数内修改外层作用域的变量而没有声明nonlocal(或global — 如果变量是在模块中),Python会创建一个新的局部变量,而不会修改外部变量。

示例:

x = 10 def foo(): x = 20 # 这是一个新的局部x,全球x没有改变 foo() print(x) # 10

要修改全局x:

def foo(): global x x = 20

对于外部函数的变量 — 使用nonlocal。


由于对主题细微差别不理解而导致的真实错误示例。


故事1

在一个教育项目中,使用嵌套函数计算调用次数。开发者写道:

def counter(): count = 0 def inc(): count += 1 return count return inc

但出现了UnboundLocalError,因为在inc()内的count被认为是新的(创建了局部count)。解决方案:声明count为nonlocal。


故事2

在web应用中,希望在处理程序内全局修改指定的缓存:

cache = {} def add_to_cache(key, value): cache[key] = value

然而如果在函数内部试图完全重写cache,例如cache = {key: value},这将创建一个新的局部cache,与全局cache没有关联,因为缺少global cache。


故事3

在一个大型ETL系统中发现了一个错误:程序员在函数内部没有明确初始化变量result,期待它会从外部作用域获取。但经过几次迭代后结果开始出错,因为内部是result += value,而不是result = result + value(没有nonlocal/global)— result在每次调用时都会重新初始化。