129 lines
4.8 KiB
Plaintext
129 lines
4.8 KiB
Plaintext
PEP: 227
|
||
Title: Statically Nested Scopes
|
||
Version: $Revision$
|
||
Author: jeremy@digicool.com (Jeremy Hylton)
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Python-Version: 2.1
|
||
Created: 01-Nov-2000
|
||
Post-History:
|
||
|
||
Abstract
|
||
|
||
This PEP proposes the addition of statically nested scoping
|
||
(lexical scoping) for Python 2.1. The current language definition
|
||
defines exactly three namespaces that are used to resolve names --
|
||
the local, global, and built-in namespaces. The addition of
|
||
nested scopes would allow resolution of unbound local names in
|
||
enclosing functions' namespaces.
|
||
|
||
One consequence of this change that will be most visible to Python
|
||
programs is that lambda statements could reference variables in
|
||
the namespaces where the lambda is defined. Currently, a lambda
|
||
statement uses default arguments to explicitly creating bindings
|
||
in the lambda's namespace.
|
||
|
||
|
||
Notes
|
||
|
||
This section describes several issues that will be fleshed out and
|
||
addressed in the final draft of the PEP. Until that draft is
|
||
ready, please direct comments to the author.
|
||
|
||
This change has been proposed many times in the past. It has
|
||
always been stymied by the possibility of creating cycles that
|
||
could not be collected by Python's reference counting garbage
|
||
collector. The additional of the cycle collector in Python 2.0
|
||
eliminates this concern.
|
||
|
||
Guido once explained that his original reservation about nested
|
||
scopes was a reaction to their overuse in Pascal. In large Pascal
|
||
programs he was familiar with, block structure was overused as an
|
||
organizing principle for the program, leading to hard-to-read
|
||
code.
|
||
|
||
Greg Ewing developed a proposal "Python Nested Lexical Scoping
|
||
Enhancement" in Aug. 1999[1]
|
||
|
||
Michael Hudson's bytecodehacks projects[2] provides facilities to
|
||
support nested scopes using the closure module.
|
||
|
||
Examples:
|
||
|
||
def make_adder(n):
|
||
def adder(x):
|
||
return x + n
|
||
return adder
|
||
add2 = make_adder(2)
|
||
add2(5) == 7
|
||
|
||
|
||
from Tkinter import *
|
||
root = Tk()
|
||
Button(root, text="Click here",
|
||
command = lambda : root.test.configure(text="..."))
|
||
|
||
|
||
One controversial issue is whether it should be possible to modify
|
||
the value of variables defined in an enclosing scope.
|
||
|
||
One part of the issue is how to specify that an assignment in the
|
||
local scope should reference to the definition of the variable in
|
||
an enclosing scope. Assignment to a variable in the current scope
|
||
creates a local variable in the scope. If the assignment is
|
||
supposed to refer to a global variable, the global statement must
|
||
be used to prevent a local name from being created. Presumably,
|
||
another keyword would be required to specify "nearest enclosing
|
||
scope."
|
||
|
||
Guido is opposed to allowing modifications (need to clarify
|
||
exactly why). If you are modifying variables bound in enclosing
|
||
scopes, you should be using a class, he says.
|
||
|
||
The problem occurs only when a program attempts to rebind the name
|
||
in the enclosing scope. A mutable object, e.g. a list or
|
||
dictionary, can be modified by a reference in a nested scope; this
|
||
is an obvious consequence of Python's reference semantics. The
|
||
ability to change mutable objects leads to an inelegant
|
||
workaround: If a program needs to rebind an immutable object,
|
||
e.g. a number or tuple, store the object in a list and have all
|
||
references to the object use this list:
|
||
|
||
def bank_account(initial_balance):
|
||
balance = [initial_balance]
|
||
def deposit(amount):
|
||
balance[0] = balance[0] + amount
|
||
def withdraw(amount):
|
||
balance[0] = balance[0] - amount
|
||
return deposit, withdraw
|
||
|
||
I would prefer for the language to support this style of
|
||
programming directly rather than encouraging programs to use this
|
||
somewhat obfuscated style. Of course, an instance would probably
|
||
be clearer in this case.
|
||
|
||
One implementation issue is how to represent the environment that
|
||
stores variables that are referenced by nested scopes. One
|
||
possibility is to add a pointer to each frame's statically
|
||
enclosing frame and walk the chain of links each time a non-local
|
||
variable is accessed. This implementation has some problems,
|
||
because access to nonlocal variables is slow and causes garbage to
|
||
accumulate unnecessarily. Another possibility is to construct an
|
||
environment for each function that provides access to only the
|
||
non-local variables. This environment would be explicitly passed
|
||
to nested functions.
|
||
|
||
|
||
References
|
||
|
||
[1] http://www.cosc.canterbury.ac.nz/~greg/python/lexscope.html
|
||
|
||
[2] http://sourceforge.net/projects/bytecodehacks/
|
||
|
||
|
||
|
||
Local Variables:
|
||
mode: indented-text
|
||
indent-tabs-mode: nil
|
||
End:
|