PEP 227, Statically Nested Scopes, Jeremy Hylton

This commit is contained in:
Barry Warsaw 2000-11-02 16:18:23 +00:00
parent 466d2315fe
commit e16bb39b89
1 changed files with 128 additions and 0 deletions

128
pep-0227.txt Normal file
View File

@ -0,0 +1,128 @@
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: