意外范围行为的文档

Documentation for unexpected scope behaviour

我今天遇到了一个最初让我感到惊讶的范围界定问题。可以通过以下方式轻松证明:

def scope():
    x = 1
    def working():
        print x
    def broken():
        import pdb; pdb.set_trace()
    working()
    broken()


Python 2.7.12 (default, Jul  1 2016, 15:12:24)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
...
>>> scope()
1
--Return--
> <stdin>(6)broken()->None
(Pdb) x
*** NameError: name 'x' is not defined

Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> def scope():
...
>>> scope()
1
--Return--
> <stdin>(6)broken()->None
(Pdb) x
*** NameError: name 'x' is not defined
(Pdb)

因此,如果在编译时 明确引用了外部范围值,则范围似乎只会包含外部范围值。这肯定是在查看字节码时似乎发生的事情:

  6           0 LOAD_GLOBAL              0 (x)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

这是 Python 如何通过检查绑定函数来区分外部和内部范围引用的产物吗?

Python scoping rules似乎无法解释:

Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:

  • the innermost scope, which is searched first, contains the local names
  • the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names

我想了解的是上面突出显示的两个部分之间的冲突:作用域是静态的,但似乎并没有兑现可访问名称的承诺。

具体来说,我要查找的是此显式行为的官方文档。

x 不是 broken 的局部变量("local" 表示在函数内部赋值),因此它不会出现在 locals() 中。

但是,如果对象没有被本地覆盖,您可以从外部范围访问对象,因此您可以在 working.

中访问它

我认为介绍 PEP227(对于 python 2.1!)涵盖了其工作原理的规范。关键部分:

The Python 2.0 definition specifies exactly three namespaces ... the local namespace, the global namespace, and the builtin namespace. According to this definition, if a function A is defined within a function B, the names bound in B are not visible in A. The proposal changes the rules so that names bound in B are visible in A (unless A contains a name binding that hides the binding in B).

...

If a name is used within* a code block, but it is not bound there and is not declared global, the use is treated as a reference to the nearest enclosing function region.

...

An analogous function [to locals() and globals()] will not be provided for nested scopes. Under this proposal, it will not be possible to gain dictionary-style access to all visible scopes.

* 强调位是关键位:您的变量尚未在代码块中使用,因此没有任何内容可以视为对封闭函数的引用。

此外,pdb是动态的运行,当没有指定命令时default (source code link)动作使用execlocalsglobals 从框架。因此,它唯一可用的变量是被检查帧的 locals()globals(),如前所述,它不包括从封闭帧捕获的变量。