我今天遇到了一个范围界定问题,最初使我感到惊讶.以下内容可以很容易地证明这一点:
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
我想了解的是上面两个突出显示的部分之间的冲突:作用域是静态的,但是似乎不支持对可访问名称的承诺.
具体来说,我要寻找的是有关此明确行为的官方文档.
解决方法:
我认为引入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)操作将exec与框架中的locals和globals一起使用.因此,唯一可用的变量是要检查的帧的locals()和globals(),如所示,它们不包括从封闭的帧中捕获的变量.