【问题标题】:How does Python variable scoping works?Python 变量作用域是如何工作的?
【发布时间】:2010-06-28 09:12:11
【问题描述】:

这希望我深入挖掘 Python 源代码,但由于 SO 上有很多人已经这样做了,我很想听听他们的指点。

>>> import os
>>> def scope():
...     print os
...     import os
... 
>>> scope()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in scope
UnboundLocalError: local variable 'os' referenced before assignment

在我看来,当解析器解释文件时,它会自动为作用域函数创建本地作用域,这使得 os 与全局作用域“分离”。

这是真的吗?有人关心我在哪里可以找到有关范围实现的更多信息吗?

编辑:另外,这不是导入的特殊情况,这也适用于通常的变量。

【问题讨论】:

    标签: python parsing scope grammar


    【解决方案1】:

    当您调用scope() 时,Python 会看到您在方法中使用了一个名为os 的局部变量(来自scope 中的import),因此这掩盖了全局os。但是,当您说print os 时,您尚未到达该行并执行本地导入,因此您在分配前看到有关参考的错误。以下是一些可能有帮助的其他示例:

    >>> x = 3
    >>> def printx():
    ...     print x # will print the global x
    ...
    >>> def printx2():
    ...     print x # will try to print the local x
    ...     x = 4
    ...
    >>> printx()
    3
    >>> printx2()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in printx2
    UnboundLocalError: local variable 'x' referenced before assignment
    

    回到你的os 例子。对os 的任何赋值都具有相同的效果:

    >>> os
    <module 'os' from 'C:\CDL_INSTALL\install\Python26\lib\os.pyc'>
    >>> def bad_os():
    ...     print os
    ...     os = "assigning a string to local os"
    ...
    >>> bad_os()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in bad_os
    UnboundLocalError: local variable 'os' referenced before assignment
    

    最后,比较这两个例子:

    >>> def example1():
    ...     print never_used # will be interpreted as a global
    ...
    >>> def example2():
    ...     print used_later # will be interpreted as the local assigned later
    ...     used_later = 42
    ...
    >>> example1()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in example1
    NameError: global name 'never_used' is not defined
    >>> example2()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in example2
    UnboundLocalError: local variable 'used_later' referenced before assignment
    

    【讨论】:

    • 谢谢 - 但是有没有关于内部实现的参考资料?我想看看解析器如何实际工作。 Python是否为每个范围创建字典/结构,并且仅在内部范围内没有任何内容时才查找外部范围?只是想理清思路。
    • 这不是解析器问题,它是运行时“查找名称与 x 匹配的最近范围”的事情。
    【解决方案2】:

    词法作用域是很常见的事情,大多数设计良好的语言,无论是解释型还是编译型都使用它。

    我已经有一段时间没有尝试过了,但请注意漂亮的“全局”关键字,以及它在下面的用法:

    o = 1
    def foo():
        global o
        o = 2
    foo()
    print o
    

    没有“global”行,对o的修改是本地化的,“print o”打印1。包含“global o”行,它打印2。我们称这种方式为我的函数(没有全局o ) 上面会有自己的变量。上面的全局东西是一种专门请求正常词法作用域异常的方法。

    真正的词法作用域是 Python 1.0 所缺乏的,而 Python 已经拥有了很长时间(如果我没记错的话,至少从 1.6 开始)。只有两个作用域,本地和全局,任何中间作用域都无法访问。

    【讨论】:

      【解决方案3】:

      函数内的任何变量绑定都会使该变量成为该函数的局部变量。 importdefclass在这方面都等价于赋值。

      所以是的,当编译器编译您的文件时,它会创建一个局部变量 os,该变量的作用域与全局 os 分开。

      有关更多信息,请参阅 Python 教程。特别是http://docs.python.org/tutorial/classes.html 第 9.2 节

      【讨论】:

        猜你喜欢
        • 2012-05-21
        • 1970-01-01
        • 1970-01-01
        • 2019-06-17
        • 2013-03-13
        • 2011-12-16
        • 2019-03-25
        相关资源
        最近更新 更多