def do_something():
print 'doing something...'
def maybe_do_it(hesitant=False):
if hesitant:
do_something = lambda: 'did nothing'
result = do_something()
print result
maybe_do_it()
这段代码的结果是:
File "scope_test.py", line 10, in <module>
maybe_do_it()
File "scope_test.py", line 7, in maybe_do_it
result = do_something()
UnboundLocalError: local variable 'do_something' referenced before assignment
但是这段代码按照预期印刷了“做了些什么......”
def do_something():
print 'doing something...'
def maybe_do_it(hesitant=False):
result = do_something()
print result
maybe_do_it()
即使if语句中的条件从未执行过,该函数是如何被覆盖的?这种情况发生在Python 2.7中 - 在Python 3中是否相同?
即使if语句中的条件从未执行过,该函数是如何被覆盖的?
变量是本地变量还是全局变量的决定是在编译时进行的。如果在函数中的任何位置都有对变量的赋值,则无论是否执行赋值,它都是局部变量。
这种情况发生在Python 2.7中 - 在python 3中是否相同?
是。
顺便说一句,在Python 2中,您可以使用覆盖此行为 exec
(不建议):
def do_something():
print 'doing something...'
def maybe_do_it(hesitant=False):
if hesitant:
exec "do_something = lambda: 'did nothing'"
result = do_something()
print result
maybe_do_it(False) # doing something...
maybe_do_it(True) # did nothing
一个 exec
松散地说,函数内部将推迟决定是全局查找变量还是本地查找执行时间。
正如文件中所述 Python执行模型:
如果名称绑定操作发生在代码块中的任何位置,
块中名称的所有使用都被视为引用
到当前块。使用名称时可能会导致错误
在绑定之前的一个街区内。这个规则很微妙。蟒蛇
缺少声明并允许进行名称绑定操作
代码块中的任何位置。代码块的局部变量
可以通过扫描块的整个文本来确定名称
绑定操作。
这是一种语言规则。这就是它的方式。 :d
当python编译为字节码时(使得 *.pyc
文件)*因为有一个 do_something = lambda: 'did nothing'
在你的功能行 do_something
现在被视为局部变量,即使控制流不在那里使用解释器。
这是出乎意料的主要原因是:
与普遍看法相反, Python已编译
这是不直观的。
从根本上说,如果你实施糟糕的设计,我认为这只会成为一个问题。当你重新分配 do_something
在你正在玩全局范围的函数中 - 这不是一个好主意。
*正如已经指出的,这实际上并不适用于编译为字节码(CPython)的Python - 它实际上是该语言的一个特性。我的解释细节(用字节码表示)仅指CPython。
是的,它在Python 3中是相同的。在大多数情况下,如果不是完全直观的行为,这是可取的。 也许你必须是荷兰人。许多人可能熟悉吊装(由JavaScript推广?)。它也发生在Python中,除了它没有 undefined
价值,Python只是提出了一个 UnboundLocalError
。比较:
> // JavaScript example
> var x = 1;
> function foo() {
if (!x) { // x is declared locally below, so locally x is undefined
var x = 2;
}
return x;
}
> foo();
2
>>> # Everything else is Python 3
>>> x = 1
>>> def foo():
... if not x: # x is bound below, which constitutes declaring it as a local
... x = 2
... return x
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment
到目前为止Python一致,但有一个(令人不安的)解决方法:
>>> def foo():
... if not 'x' in locals():
... x = 2
... return x
...
>>> foo()
2
这是有效的,我们已经 被告知
可以通过扫描块的整个文本以确定名称绑定操作来确定代码块的局部变量。
但事实并非如此 locals()
给我们所有的本地名字?显然不是。事实上,尽管有前面的声明,Python暗示本地符号表可以改变 的描述 locals()
内置:
更新并返回代表该字典的字典 当前 [强调我的]当地符号表。
我曾经想过这个词 当前 提到这些值,现在我认为它也指的是键。但最终我认为这意味着什么呢 没门 (除了转储和解析框架的源代码之外)枚举本地声明的所有名称(这并不是说你不能使用try / except UnboundLocalError来确定特定名称是否是本地名称。)
def foo():
# Some code, including bindings
del x, y, z # or any other local names
# From this point, is it programmatically knowable what names are local?
我认为,这是具有隐式声明的语言和具有显式声明的语言之间的根本区别。