Reputation: 14962
I hit a scoping issue today that initially surprised me. It can be readily demonstrated by the following:
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)
So it appears a scope will only contain outer-scope values if there's an explicit reference to them at compilation time. This is certainly what appears to happen when looking at the bytecode:
6 0 LOAD_GLOBAL 0 (x)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
Is this an artifact of how Python differentiates between outer & inner scope references by examining the function for bindings?
This does not appear to be explained by the 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
What I'm trying to understand is the conflict between the two highlighted parts above: scopes are static but the promise of what names are accessible doesn't seem to be upheld.
Specifically, what I'm looking for is official documentation of this explicit behaviour.
Upvotes: 3
Views: 122
Reputation: 8159
I think the specification of how this works is covered by the introducing PEP227 (for python 2.1!). Key parts:
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.
* emphasised bit being the key bit: Your variable has not been used within a code block, so therefore there is nothing to treat as a reference to the enclosing function.
Furthermore, pdb
is running dynamically and the default
(source code link) action when no command has been specified uses exec
with locals
and globals
from the frame. Therefore the only variables available to it are locals()
and globals()
of the frame being inspected, which as indicated do not include captured variables from enclosing frames.
Upvotes: 1
Reputation: 66837
x
is not local to broken
("local" meaning assigned inside the function), so it won't show up in locals()
.
However, you can access objects from the outer scope if they are not shadowed by a local, so you can access it in working
.
Upvotes: 2