我今天遇到一个范围问题,最初让我感到惊讶。它可以通过以下方式轻松证明:
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如何区分外部和外部的工件吗?通过检查绑定函数来确定内部范围?
似乎没有解释这一点虽然范围是静态确定的,但它们是动态使用的。在执行期间的任何时间,至少有三个嵌套作用域,其名称空间可以直接访问:
- 首先搜索的最里面的范围包含本地名称
- 从最近的封闭范围开始搜索的任何封闭函数的范围包含非本地名称,但也包含非全局名称
我试图理解的是上面两个突出部分之间的冲突:范围是静态的,但似乎可以维护可访问名称的承诺。
具体来说,我正在寻找的是这种明确行为的官方文档。
答案 0 :(得分:2)
x
不是broken
的本地人(&#34;本地&#34;意味着在函数内分配),因此它不会显示在locals()
中。
但是,如果对象没有被本地阴影,则可以从外部作用域访问对象,因此您可以在working
中访问它。
答案 1 :(得分:1)
我认为介绍What is the difference between should and must in scala testing?(对于python 2.1!)涵盖了如何工作的规范。关键部分:
Python 2.0定义正好指定了三个名称空间......本地名称空间,全局名称空间, 和内置命名空间。根据这个定义,如果一个 函数A在函数B中定义,名称在B中绑定 在A中不可见。提案会更改规则以便这样做 B中绑定的名称在A中可见(除非A包含名称 在B)中隐藏绑定的绑定。
...
如果在 *代码块中使用名称,但它没有绑定 并且未声明为全局,该用途被视为对其的引用 最近的封闭功能区。
...
不会为嵌套作用域提供类似函数[ to locals()和globals()]。根据此提案,将无法获得对所有可见范围的字典式访问。
*强调位为关键位:您的变量未在代码块中使用,因此没有什么可以作为对封闭函数的引用。
此外,pdb
动态运行,未指定命令时PEP227操作使用exec
和locals
来自框架globals
。因此,唯一可用的变量是被检查帧的locals()
和globals()
,如图所示,不包括从封闭帧中捕获的变量。