Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 非直观UnboundLocalError行为的原因_Python - Fatal编程技术网

Python 非直观UnboundLocalError行为的原因

Python 非直观UnboundLocalError行为的原因,python,Python,注:有一个非常类似的问题。不过,请容忍我;我的问题不是“为什么会发生错误”,而是“为什么Python实现为在这种情况下抛出错误。” 我只是被这件事绊倒了: a = 5 def x() print a a = 6 x() 抛出一个取消绑定的LocalException。现在,我确实知道了为什么会发生这种情况(稍后在这个范围内,a是绑定的,因此a被认为是整个范围内的局部) 在这种情况下: a = 5 def x() print b b = 6 x() 这很有道理。

注:有一个非常类似的问题。不过,请容忍我;我的问题不是“为什么会发生错误”,而是“为什么Python实现为在这种情况下抛出错误。”

我只是被这件事绊倒了:

a = 5
def x()
    print a
    a = 6
x()
抛出一个
取消绑定的LocalException
。现在,我确实知道了为什么会发生这种情况(稍后在这个范围内,
a
是绑定的,因此
a
被认为是整个范围内的局部)

在这种情况下:

a = 5
def x()
    print b
    b = 6
x()

这很有道理。但第一个案例有一个直观的逻辑,这意味着:

a = 5
def x()
    print globals()["a"]
    a = 6 # local assignment
x()
我想“直觉”版本不被允许是有原因的,但它是什么?尽管这可能是“显式优于隐式”的情况,但在
globals()
上摆弄总是让我觉得有点不干净

为了更好地理解这一点,发生在我身上的实际情况是,我不得不暂时改变别人的剧本。在我的(短期)更改中,我在脚本运行时进行了一些文件重命名,因此我插入了

import os
os.rename("foo", "bar")
在剧本中。此插入发生在函数内部。模块已经在顶层导入了
os
(我没有检查),一些
os.somefunction
调用在函数内部,但在我插入之前。这些调用显然触发了一个
UnboundLocalException


那么,有人能向我解释一下这个实现背后的原因吗?是为了防止用户犯错误吗?“直观”的方式会让字节码编译器的事情变得更复杂吗?还是有一种我没有想到的可能的模糊性?

在相同的线性代码流中,相同的名称指的是完全不同的变量,这是一种令人难以置信的复杂性,让人震惊。考虑:

def aaaargh(alist):
  for x in alist:
    print a
    a = 23
这段代码在Python上所需的变体中应该做什么?相同的
print
语句中的
a
是否引用循环第一段与第二段上完全不同且不相关的变量(假设存在第二段)?它的工作方式是否与非循环代码的工作方式有所不同?说真的,这种疯狂是在撒谎——甚至不考虑可怕的实现问题,只是试图记录和教授这一点可能会让我转换语言


语言、实施者、教师、学习者、实践者承担所有这些概念负担的根本动机是什么?支持和鼓励半隐藏、非显式地使用全局变量?!这似乎不是一个值得追求的目标,不是吗

我认为可能存在歧义

a = 5
def x():
    print a
    a = 6  # could be local or trying to update the global variable
x()
正如你所设想的那样:

a = 5
def x():
    print globals()["a"]
    a = 6 # local assignment
x()
或者,他们可能希望将全局变量更新为6:

a = 5
def x():
    global a
    print a
    a = 6
x()

这是范围界定的一个基本副作用。python开发人员认为全局变量不应该在您试图使用它的范围内可用。以此为例:

a = 5
def x():
    a = 6
    print a
x()
print a
这将输出
65

无论如何都需要全局变量,因此python开发人员限制了这一点。您必须显式地使全局变量可访问才能访问它。这实际上是为了防止歧义。考虑这一点:

a = 5
def x():
    a = 6
    print a
    y()
def y():
    global a
    a = a + 1
    print a
x()
print a
如果
x()
认为
a
是本地的,并进行了赋值,则会输出
6 7
。编写
x()
的人可能没有考虑到
y()
将使用名为
a
的全局变量。从而导致
y()
异常动作。幸运的是,python范围映射使得
x()
的开发人员不必担心
y()
的开发人员如何实现
y()
,只需要它做它应该做的事情。因此,这会像预期的那样输出
6
(图)


因此,
UnboundLocalException
非常直观。

+1,可以说,“这种方式是疯狂的。”。编写语言似乎比使用语言复杂得多。我同意,但如果变量“a”没有在内部范围内声明,Python为什么会在外部范围内寻找变量呢?这似乎也鼓励了“半隐藏全局变量”的使用,而且当存在globals关键字来记录对外部范围的引用时,这似乎是一个特别没有意义的快捷方式……只是为了说明:我没有试图重新定义Python或创建“我想要的变量”我从来不想说这样做的决定是不好的,我只是想了解原因。回答得不错,+1.ire_和_诅咒:在外部作用域中查找未在本地作用域中声明的名称很有帮助,因为它允许您引用在全局作用域中定义/导入的函数、类和模块。共享全局状态不错;共享可变全局状态是有风险的。@Marius Gedminas:谢谢,这是一个非常有用的解释+1我在这里补充了一个后续问题:“但第一个案例有一个直观的逻辑。”这是一个不必要的宽泛陈述。有些人在这些事情上没有“直觉”。一些人试图避免做出假设,只是阅读语言手册并接受它所说的。如果你试图避免声称你的特定“直觉”是一种让许多人困惑的一般事物,这会很有帮助。@SLott虽然我基本上同意你的观点,但请不要把话塞进我的嘴里。我的问题是关于理解语言设计的选择;我从来没有说过这会让任何人感到困惑,更不用说“很多人”。这是完全错误的:你可以从函数中读取全局变量,这很好(否则导入对你没有多大帮助)。但分配总是会产生一个局部的。