【发布时间】:2020-01-07 21:30:27
【问题描述】:
我认为我根本不了解 Python 是如何处理变量范围和名称解析等事情的。特别是,下面的函数broken() 不起作用这一事实真的让我感到惊讶。而且,尽管我已经在网上搜索了一段时间以寻找有用的解释,但我仍然不明白。任何人都可以解释或链接到一个很好的描述这些东西如何在 Python 中工作,有足够的细节,阅读相关材料后为什么broken() 不起作用似乎很明显?
# Why does this code work fine
def okay0():
def foo():
L = []
def bar():
L.append(5)
bar()
return L
foo()
# and so does this
def okay1():
def foo():
def bar():
L.append(5)
L = []
bar()
return L
foo()
# but the following code raises an exception?
def broken():
def foo():
L = []
bar()
return L
def bar():
L.append(5)
foo()
# Example
test_list = [okay0, okay1, broken]
for test_function in test_list:
try:
test_function()
except:
print("broken")
else:
print("okay")
【问题讨论】:
-
你试图从不同的范围访问一个本地,即
bar的范围内,L不存在。 -
在
broken()中,在foo()内部L是一个局部变量(因为它有一个赋值,并且没有global声明)。除了foo()之外,唯一可能被引用(甚至存在)的地方是嵌套在foo()中的函数。 -
有人曾经说过,要真正获得 Python,你必须了解它的 namespaces。这听起来很简单,但它实际上是用这种语言提供的非常深刻的建议。如果你问自己这种类型的问题,你就在路上了!
-
请注意,具有词法作用域的任何语言(包括 Java 或 C/C++)都会以相同的方式运行......所以并不是你不理解 Python,您似乎不太了解 lexical scoping,这是自 70 年代以来几乎所有语言的 范围规则。
-
@GiacomoAlzetta。对一个有趣且发人深省的问题不必要地刻薄。当然,这不是更广泛的 Python 社区会采用的基调,而且对它更好。