代码之家  ›  专栏  ›  技术社区  ›  balpha

非故意非本地错误行为的原因

  •  4
  • balpha  · 技术社区  · 15 年前

    注:有一个非常相似的问题 here . 不过,请原谅我;我的问题不是“为什么会发生错误”,而是“为什么在这种情况下使用Python来抛出错误”。

    我只是偶然发现:

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

    抛出一个 UnboundLocalException . 现在,我知道为什么会发生这种情况(稍后在这个范围内, 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 在函数内部但在插入之前调用。这些电话显然触发了 未绑定的本地异常 .

    那么,有人能向我解释这个实现背后的原因吗?是为了防止用户犯错误吗?“直观”的方式会使字节码编译器的工作变得更复杂吗?或者有没有可能是我没想到的模棱两可?

    3 回复  |  直到 11 年前
        1
  •  5
  •   Alex Martelli    15 年前

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

    def aaaargh(alist):
      for x in alist:
        print a
        a = 23
    

    在您希望的Python变体中,这段代码应该做什么?有 a 在非常相同的 print 语句引用循环第一段与第二段完全不同且不相关的变量(假设有第二段)?即使对于一个项目列表,它的工作方式是否与非循环代码的工作方式不同?说真的,这就是疯狂的谎言——甚至不考虑可怕的实现问题,只是试图记录和教授这些东西,可能会让我转换语言。

    语言、实现者、教师、学习者、实践者承担所有这些概念负担的基础动力是什么?-- 支持和鼓励半隐藏、非显式地使用全局变量 ?!这似乎不是一个有价值的目标,是不是现在?!

        2
  •  1
  •   tgray    15 年前

    我认为可能存在歧义。

    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()
    
        3
  •  0
  •   Community CDub    8 年前

    这是范围界定的基本副作用。Python开发人员决定,全局变量不应该在您试图使用它的范围内可用。例如:

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

    这个输出 6 5 .

    它是 generally considered bad practice 无论如何要有全局变量,所以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 6 7 . 无论是谁写的 () 可能没有考虑到 y() 将使用名为 . 从而导致 () 反常地行动。幸运的是,python scopping使得 () 不必担心 () 实施 () 只有它做它应该做的。因此,该输出 6 6 6 (数字),就像它应该的那样。

    因此, UnboundLocalException 非常直观。