reSTify PEP 227 (#373)

This commit is contained in:
Huang Huang 2017-09-13 07:25:44 +08:00 committed by Guido van Rossum
parent 3f83280386
commit 0f008dd229
1 changed files with 337 additions and 314 deletions

View File

@ -5,128 +5,136 @@ Last-Modified: $Date$
Author: jeremy@alum.mit.edu (Jeremy Hylton) Author: jeremy@alum.mit.edu (Jeremy Hylton)
Status: Final Status: Final
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: 01-Nov-2000 Created: 01-Nov-2000
Python-Version: 2.1 Python-Version: 2.1
Post-History: Post-History:
Abstract Abstract
========
This PEP describes the addition of statically nested scoping This PEP describes the addition of statically nested scoping
(lexical scoping) for Python 2.2, and as a source level option (lexical scoping) for Python 2.2, and as a source level option
for python 2.1. In addition, Python 2.1 will issue warnings about for python 2.1. In addition, Python 2.1 will issue warnings about
constructs whose meaning may change when this feature is enabled. constructs whose meaning may change when this feature is enabled.
The old language definition (2.0 and before) defines exactly three The old language definition (2.0 and before) defines exactly three
namespaces that are used to resolve names -- the local, global, namespaces that are used to resolve names -- the local, global,
and built-in namespaces. The addition of nested scopes allows and built-in namespaces. The addition of nested scopes allows
resolution of unbound local names in enclosing functions' resolution of unbound local names in enclosing functions'
namespaces. namespaces.
The most visible consequence of this change is that lambdas (and The most visible consequence of this change is that lambdas (and
other nested functions) can reference variables defined in the other nested functions) can reference variables defined in the
surrounding namespace. Currently, lambdas must often use default surrounding namespace. Currently, lambdas must often use default
arguments to explicitly creating bindings in the lambda's arguments to explicitly creating bindings in the lambda's
namespace. namespace.
Introduction Introduction
============
This proposal changes the rules for resolving free variables in This proposal changes the rules for resolving free variables in
Python functions. The new name resolution semantics will take Python functions. The new name resolution semantics will take
effect with Python 2.2. These semantics will also be available in effect with Python 2.2. These semantics will also be available in
Python 2.1 by adding "from __future__ import nested_scopes" to the Python 2.1 by adding "from __future__ import nested_scopes" to the
top of a module. (See PEP 236.) top of a module. (See PEP 236.)
The Python 2.0 definition specifies exactly three namespaces to The Python 2.0 definition specifies exactly three namespaces to
check for each name -- the local namespace, the global namespace, check for each name -- the local namespace, the global namespace,
and the builtin namespace. According to this definition, if a and the builtin namespace. According to this definition, if a
function A is defined within a function B, the names bound in B 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 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 names bound in B are visible in A (unless A contains a name
binding that hides the binding in B). binding that hides the binding in B).
This specification introduces rules for lexical scoping that are This specification introduces rules for lexical scoping that are
common in Algol-like languages. The combination of lexical common in Algol-like languages. The combination of lexical
scoping and existing support for first-class functions is scoping and existing support for first-class functions is
reminiscent of Scheme. reminiscent of Scheme.
The changed scoping rules address two problems -- the limited The changed scoping rules address two problems -- the limited
utility of lambda expressions (and nested functions in general), utility of lambda expressions (and nested functions in general),
and the frequent confusion of new users familiar with other and the frequent confusion of new users familiar with other
languages that support nested lexical scopes, e.g. the inability languages that support nested lexical scopes, e.g. the inability
to define recursive functions except at the module level. to define recursive functions except at the module level.
The lambda expression yields an unnamed function that evaluates a The lambda expression yields an unnamed function that evaluates a
single expression. It is often used for callback functions. In single expression. It is often used for callback functions. In
the example below (written using the Python 2.0 rules), any name the example below (written using the Python 2.0 rules), any name
used in the body of the lambda must be explicitly passed as a used in the body of the lambda must be explicitly passed as a
default argument to the lambda. default argument to the lambda.
::
from Tkinter import * from Tkinter import *
root = Tk() root = Tk()
Button(root, text="Click here", Button(root, text="Click here",
command=lambda root=root: root.test.configure(text="...")) command=lambda root=root: root.test.configure(text="..."))
This approach is cumbersome, particularly when there are several This approach is cumbersome, particularly when there are several
names used in the body of the lambda. The long list of default names used in the body of the lambda. The long list of default
arguments obscures the purpose of the code. The proposed arguments obscures the purpose of the code. The proposed
solution, in crude terms, implements the default argument approach solution, in crude terms, implements the default argument approach
automatically. The "root=root" argument can be omitted. automatically. The "root=root" argument can be omitted.
The new name resolution semantics will cause some programs to The new name resolution semantics will cause some programs to
behave differently than they did under Python 2.0. In some cases, behave differently than they did under Python 2.0. In some cases,
programs will fail to compile. In other cases, names that were programs will fail to compile. In other cases, names that were
previously resolved using the global namespace will be resolved previously resolved using the global namespace will be resolved
using the local namespace of an enclosing function. In Python using the local namespace of an enclosing function. In Python
2.1, warnings will be issued for all statements that will behave 2.1, warnings will be issued for all statements that will behave
differently. differently.
Specification Specification
=============
Python is a statically scoped language with block structure, in Python is a statically scoped language with block structure, in
the traditional of Algol. A code block or region, such as a the traditional of Algol. A code block or region, such as a
module, class definition, or function body, is the basic unit of a module, class definition, or function body, is the basic unit of a
program. program.
Names refer to objects. Names are introduced by name binding Names refer to objects. Names are introduced by name binding
operations. Each occurrence of a name in the program text refers operations. Each occurrence of a name in the program text refers
to the binding of that name established in the innermost function to the binding of that name established in the innermost function
block containing the use. block containing the use.
The name binding operations are argument declaration, assignment, The name binding operations are argument declaration, assignment,
class and function definition, import statements, for statements, class and function definition, import statements, for statements,
and except clauses. Each name binding occurs within a block and except clauses. Each name binding occurs within a block
defined by a class or function definition or at the module level defined by a class or function definition or at the module level
(the top-level code block). (the top-level code block).
If a name is bound anywhere within a code block, all uses of the If a name is bound anywhere within a code block, all uses of the
name within the block are treated as references to the current name within the block are treated as references to the current
block. (Note: This can lead to errors when a name is used within block. (Note: This can lead to errors when a name is used within
a block before it is bound.) a block before it is bound.)
If the global statement occurs within a block, all uses of the If the global statement occurs within a block, all uses of the
name specified in the statement refer to the binding of that name name specified in the statement refer to the binding of that name
in the top-level namespace. Names are resolved in the top-level in the top-level namespace. Names are resolved in the top-level
namespace by searching the global namespace, i.e. the namespace of namespace by searching the global namespace, i.e. the namespace of
the module containing the code block, and in the builtin the module containing the code block, and in the builtin
namespace, i.e. the namespace of the __builtin__ module. The namespace, i.e. the namespace of the ``__builtin__`` module. The
global namespace is searched first. If the name is not found global namespace is searched first. If the name is not found
there, the builtin namespace is searched. The global statement there, the builtin namespace is searched. The global statement
must precede all uses of the name. must precede all uses of the name.
If a name is used within a code block, but it is not bound there 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 and is not declared global, the use is treated as a reference to
the nearest enclosing function region. (Note: If a region is the nearest enclosing function region. (Note: If a region is
contained within a class definition, the name bindings that occur contained within a class definition, the name bindings that occur
in the class block are not visible to enclosed functions.) in the class block are not visible to enclosed functions.)
A class definition is an executable statement that may contain A class definition is an executable statement that may contain
uses and definitions of names. These references follow the normal uses and definitions of names. These references follow the normal
rules for name resolution. The namespace of the class definition rules for name resolution. The namespace of the class definition
becomes the attribute dictionary of the class. becomes the attribute dictionary of the class.
The following operations are name binding operations. If they The following operations are name binding operations. If they
occur within a block, they introduce new local names in the occur within a block, they introduce new local names in the
current block unless there is also a global declaration. current block unless there is also a global declaration.
::
Function definition: def name ... Function definition: def name ...
Argument declaration: def f(...name...), lambda ...name... Argument declaration: def f(...name...), lambda ...name...
@ -137,89 +145,93 @@ Specification
Implicit assignment: names are bound by for statements and except Implicit assignment: names are bound by for statements and except
clauses clauses
There are several cases where Python statements are illegal when There are several cases where Python statements are illegal when
used in conjunction with nested scopes that contain free used in conjunction with nested scopes that contain free
variables. variables.
If a variable is referenced in an enclosed scope, it is an error If a variable is referenced in an enclosed scope, it is an error
to delete the name. The compiler will raise a SyntaxError for to delete the name. The compiler will raise a ``SyntaxError`` for
'del name'. 'del name'.
If the wild card form of import (import *) is used in a function If the wild card form of import (``import *``) is used in a function
and the function contains a nested block with free variables, the and the function contains a nested block with free variables, the
compiler will raise a SyntaxError. compiler will raise a ``SyntaxError``.
If exec is used in a function and the function contains a nested If exec is used in a function and the function contains a nested
block with free variables, the compiler will raise a SyntaxError block with free variables, the compiler will raise a ``SyntaxError``
unless the exec explicitly specifies the local namespace for the unless the exec explicitly specifies the local namespace for the
exec. (In other words, "exec obj" would be illegal, but exec. (In other words, "exec obj" would be illegal, but
"exec obj in ns" would be legal.) "exec obj in ns" would be legal.)
If a name bound in a function scope is also the name of a module If a name bound in a function scope is also the name of a module
global name or a standard builtin name, and the function contains global name or a standard builtin name, and the function contains
a nested function scope that references the name, the compiler a nested function scope that references the name, the compiler
will issue a warning. The name resolution rules will result in will issue a warning. The name resolution rules will result in
different bindings under Python 2.0 than under Python 2.2. The different bindings under Python 2.0 than under Python 2.2. The
warning indicates that the program may not run correctly with all warning indicates that the program may not run correctly with all
versions of Python. versions of Python.
Discussion Discussion
==========
The specified rules allow names defined in a function to be The specified rules allow names defined in a function to be
referenced in any nested function defined with that function. The referenced in any nested function defined with that function. The
name resolution rules are typical for statically scoped languages, name resolution rules are typical for statically scoped languages,
with three primary exceptions: with three primary exceptions:
- Names in class scope are not accessible. - Names in class scope are not accessible.
- The global statement short-circuits the normal rules. - The global statement short-circuits the normal rules.
- Variables are not declared. - Variables are not declared.
Names in class scope are not accessible. Names are resolved in Names in class scope are not accessible. Names are resolved in
the innermost enclosing function scope. If a class definition the innermost enclosing function scope. If a class definition
occurs in a chain of nested scopes, the resolution process skips occurs in a chain of nested scopes, the resolution process skips
class definitions. This rule prevents odd interactions between class definitions. This rule prevents odd interactions between
class attributes and local variable access. If a name binding class attributes and local variable access. If a name binding
operation occurs in a class definition, it creates an attribute on operation occurs in a class definition, it creates an attribute on
the resulting class object. To access this variable in a method, the resulting class object. To access this variable in a method,
or in a function nested within a method, an attribute reference or in a function nested within a method, an attribute reference
must be used, either via self or via the class name. must be used, either via self or via the class name.
An alternative would have been to allow name binding in class An alternative would have been to allow name binding in class
scope to behave exactly like name binding in function scope. This scope to behave exactly like name binding in function scope. This
rule would allow class attributes to be referenced either via rule would allow class attributes to be referenced either via
attribute reference or simple name. This option was ruled out attribute reference or simple name. This option was ruled out
because it would have been inconsistent with all other forms of because it would have been inconsistent with all other forms of
class and instance attribute access, which always use attribute class and instance attribute access, which always use attribute
references. Code that used simple names would have been obscure. references. Code that used simple names would have been obscure.
The global statement short-circuits the normal rules. Under the The global statement short-circuits the normal rules. Under the
proposal, the global statement has exactly the same effect that it proposal, the global statement has exactly the same effect that it
does for Python 2.0. It is also noteworthy because it allows name does for Python 2.0. It is also noteworthy because it allows name
binding operations performed in one block to change bindings in binding operations performed in one block to change bindings in
another block (the module). another block (the module).
Variables are not declared. If a name binding operation occurs Variables are not declared. If a name binding operation occurs
anywhere in a function, then that name is treated as local to the anywhere in a function, then that name is treated as local to the
function and all references refer to the local binding. If a function and all references refer to the local binding. If a
reference occurs before the name is bound, a NameError is raised. reference occurs before the name is bound, a NameError is raised.
The only kind of declaration is the global statement, which allows The only kind of declaration is the global statement, which allows
programs to be written using mutable global variables. As a programs to be written using mutable global variables. As a
consequence, it is not possible to rebind a name defined in an consequence, it is not possible to rebind a name defined in an
enclosing scope. An assignment operation can only bind a name in enclosing scope. An assignment operation can only bind a name in
the current scope or in the global scope. The lack of the current scope or in the global scope. The lack of
declarations and the inability to rebind names in enclosing scopes declarations and the inability to rebind names in enclosing scopes
are unusual for lexically scoped languages; there is typically a are unusual for lexically scoped languages; there is typically a
mechanism to create name bindings (e.g. lambda and let in Scheme) mechanism to create name bindings (e.g. lambda and let in Scheme)
and a mechanism to change the bindings (set! in Scheme). and a mechanism to change the bindings (set! in Scheme).
XXX Alex Martelli suggests comparison with Java, which does not XXX Alex Martelli suggests comparison with Java, which does not
allow name bindings to hide earlier bindings. allow name bindings to hide earlier bindings.
Examples Examples
========
A few examples are included to illustrate the way the rules work. A few examples are included to illustrate the way the rules work.
XXX Explain the examples XXX Explain the examples
::
>>> def make_adder(base): >>> def make_adder(base):
... def adder(x): ... def adder(x):
@ -259,8 +271,8 @@ Examples
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
AttributeError: _private AttributeError: _private
An example from Tim Peters demonstrates the potential pitfalls of An example from Tim Peters demonstrates the potential pitfalls of
nested scopes in the absence of declarations: nested scopes in the absence of declarations::
i = 6 i = 6
def f(x): def f(x):
@ -273,22 +285,23 @@ Examples
pass pass
g() g()
The call to g() will refer to the variable i bound in f() by the for The call to ``g()`` will refer to the variable i bound in ``f()`` by the for
loop. If g() is called before the loop is executed, a NameError will loop. If ``g()`` is called before the loop is executed, a NameError will
be raised. be raised.
XXX need some counterexamples XXX need some counterexamples
Backwards compatibility Backwards compatibility
=======================
There are two kinds of compatibility problems caused by nested There are two kinds of compatibility problems caused by nested
scopes. In one case, code that behaved one way in earlier scopes. In one case, code that behaved one way in earlier
versions behaves differently because of nested scopes. In the versions behaves differently because of nested scopes. In the
other cases, certain constructs interact badly with nested scopes other cases, certain constructs interact badly with nested scopes
and will trigger SyntaxErrors at compile time. and will trigger SyntaxErrors at compile time.
The following example from Skip Montanaro illustrates the first The following example from Skip Montanaro illustrates the first
kind of problem: kind of problem::
x = 1 x = 1
def f1(): def f1():
@ -297,26 +310,26 @@ Backwards compatibility
print x print x
inner() inner()
Under the Python 2.0 rules, the print statement inside inner() Under the Python 2.0 rules, the print statement inside ``inner()``
refers to the global variable x and will print 1 if f1() is refers to the global variable x and will print 1 if ``f1()`` is
called. Under the new rules, it refers to the f1()'s namespace, called. Under the new rules, it refers to the ``f1()``'s namespace,
the nearest enclosing scope with a binding. the nearest enclosing scope with a binding.
The problem occurs only when a global variable and a local The problem occurs only when a global variable and a local
variable share the same name and a nested function uses that name variable share the same name and a nested function uses that name
to refer to the global variable. This is poor programming to refer to the global variable. This is poor programming
practice, because readers will easily confuse the two different practice, because readers will easily confuse the two different
variables. One example of this problem was found in the Python variables. One example of this problem was found in the Python
standard library during the implementation of nested scopes. standard library during the implementation of nested scopes.
To address this problem, which is unlikely to occur often, the To address this problem, which is unlikely to occur often, the
Python 2.1 compiler (when nested scopes are not enabled) issues a Python 2.1 compiler (when nested scopes are not enabled) issues a
warning. warning.
The other compatibility problem is caused by the use of 'import *' The other compatibility problem is caused by the use of ``import *``
and 'exec' in a function body, when that function contains a and 'exec' in a function body, when that function contains a
nested scope and the contained scope has free variables. For nested scope and the contained scope has free variables. For
example: example::
y = 1 y = 1
def f(): def f():
@ -325,120 +338,127 @@ Backwards compatibility
return y return y
... ...
At compile-time, the compiler cannot tell whether an exec that At compile-time, the compiler cannot tell whether an exec that
operates on the local namespace or an import * will introduce operates on the local namespace or an ``import *`` will introduce
name bindings that shadow the global y. Thus, it is not possible name bindings that shadow the global y. Thus, it is not possible
to tell whether the reference to y in g() should refer to the to tell whether the reference to y in ``g()`` should refer to the
global or to a local name in f(). global or to a local name in ``f()``.
In discussion of the python-list, people argued for both possible In discussion of the python-list, people argued for both possible
interpretations. On the one hand, some thought that the reference interpretations. On the one hand, some thought that the reference
in g() should be bound to a local y if one exists. One problem in ``g()`` should be bound to a local y if one exists. One problem
with this interpretation is that it is impossible for a human with this interpretation is that it is impossible for a human
reader of the code to determine the binding of y by local reader of the code to determine the binding of y by local
inspection. It seems likely to introduce subtle bugs. The other inspection. It seems likely to introduce subtle bugs. The other
interpretation is to treat exec and import * as dynamic features interpretation is to treat exec and import * as dynamic features
that do not effect static scoping. Under this interpretation, the that do not effect static scoping. Under this interpretation, the
exec and import * would introduce local names, but those names exec and import * would introduce local names, but those names
would never be visible to nested scopes. In the specific example would never be visible to nested scopes. In the specific example
above, the code would behave exactly as it did in earlier versions above, the code would behave exactly as it did in earlier versions
of Python. of Python.
Since each interpretation is problematic and the exact meaning Since each interpretation is problematic and the exact meaning
ambiguous, the compiler raises an exception. The Python 2.1 ambiguous, the compiler raises an exception. The Python 2.1
compiler issues a warning when nested scopes are not enabled. compiler issues a warning when nested scopes are not enabled.
A brief review of three Python projects (the standard library, A brief review of three Python projects (the standard library,
Zope, and a beta version of PyXPCOM) found four backwards Zope, and a beta version of PyXPCOM) found four backwards
compatibility issues in approximately 200,000 lines of code. compatibility issues in approximately 200,000 lines of code.
There was one example of case #1 (subtle behavior change) and two There was one example of case #1 (subtle behavior change) and two
examples of import * problems in the standard library. examples of ``import *`` problems in the standard library.
(The interpretation of the import * and exec restriction that was (The interpretation of the ``import *`` and exec restriction that was
implemented in Python 2.1a2 was much more restrictive, based on implemented in Python 2.1a2 was much more restrictive, based on
language that in the reference manual that had never been language that in the reference manual that had never been
enforced. These restrictions were relaxed following the release.) enforced. These restrictions were relaxed following the release.)
Compatibility of C API Compatibility of C API
======================
The implementation causes several Python C API functions to The implementation causes several Python C API functions to
change, including PyCode_New(). As a result, C extensions may change, including ``PyCode_New()``. As a result, C extensions may
need to be updated to work correctly with Python 2.1. need to be updated to work correctly with Python 2.1.
locals() / vars() locals() / vars()
=================
These functions return a dictionary containing the current scope's These functions return a dictionary containing the current scope's
local variables. Modifications to the dictionary do not affect local variables. Modifications to the dictionary do not affect
the values of variables. Under the current rules, the use of the values of variables. Under the current rules, the use of
locals() and globals() allows the program to gain access to all ``locals()`` and ``globals()`` allows the program to gain access to all
the namespaces in which names are resolved. the namespaces in which names are resolved.
An analogous function will not be provided for nested scopes. An analogous function will not be provided for nested scopes.
Under this proposal, it will not be possible to gain Under this proposal, it will not be possible to gain
dictionary-style access to all visible scopes. dictionary-style access to all visible scopes.
Warnings and Errors Warnings and Errors
===================
The compiler will issue warnings in Python 2.1 to help identify The compiler will issue warnings in Python 2.1 to help identify
programs that may not compile or run correctly under future programs that may not compile or run correctly under future
versions of Python. Under Python 2.2 or Python 2.1 if the versions of Python. Under Python 2.2 or Python 2.1 if the
nested_scopes future statement is used, which are collectively ``nested_scopes`` future statement is used, which are collectively
referred to as "future semantics" in this section, the compiler referred to as "future semantics" in this section, the compiler
will issue SyntaxErrors in some cases. will issue SyntaxErrors in some cases.
The warnings typically apply when a function that contains a The warnings typically apply when a function that contains a
nested function that has free variables. For example, if function nested function that has free variables. For example, if function
F contains a function G and G uses the builtin len(), then F is a F contains a function G and G uses the builtin ``len()``, then F is a
function that contains a nested function (G) with a free variable function that contains a nested function (G) with a free variable
(len). The label "free-in-nested" will be used to describe these (len). The label "free-in-nested" will be used to describe these
functions. functions.
import * used in function scope import * used in function scope
-------------------------------
The language reference specifies that import * may only occur The language reference specifies that ``import *`` may only occur
in a module scope. (Sec. 6.11) The implementation of C in a module scope. (Sec. 6.11) The implementation of C
Python has supported import * at the function scope. Python has supported ``import *`` at the function scope.
If import * is used in the body of a free-in-nested function, If ``import *`` is used in the body of a free-in-nested function,
the compiler will issue a warning. Under future semantics, the compiler will issue a warning. Under future semantics,
the compiler will raise a SyntaxError. the compiler will raise a ``SyntaxError``.
bare exec in function scope bare exec in function scope
---------------------------
The exec statement allows two optional expressions following The exec statement allows two optional expressions following
the keyword "in" that specify the namespaces used for locals the keyword "in" that specify the namespaces used for locals
and globals. An exec statement that omits both of these and globals. An exec statement that omits both of these
namespaces is a bare exec. namespaces is a bare exec.
If a bare exec is used in the body of a free-in-nested If a bare exec is used in the body of a free-in-nested
function, the compiler will issue a warning. Under future function, the compiler will issue a warning. Under future
semantics, the compiler will raise a SyntaxError. semantics, the compiler will raise a ``SyntaxError``.
local shadows global local shadows global
--------------------
If a free-in-nested function has a binding for a local If a free-in-nested function has a binding for a local
variable that (1) is used in a nested function and (2) is the variable that (1) is used in a nested function and (2) is the
same as a global variable, the compiler will issue a warning. same as a global variable, the compiler will issue a warning.
Rebinding names in enclosing scopes Rebinding names in enclosing scopes
-----------------------------------
There are technical issues that make it difficult to support There are technical issues that make it difficult to support
rebinding of names in enclosing scopes, but the primary reason rebinding of names in enclosing scopes, but the primary reason
that it is not allowed in the current proposal is that Guido is that it is not allowed in the current proposal is that Guido is
opposed to it. His motivation: it is difficult to support, opposed to it. His motivation: it is difficult to support,
because it would require a new mechanism that would allow the because it would require a new mechanism that would allow the
programmer to specify that an assignment in a block is supposed to programmer to specify that an assignment in a block is supposed to
rebind the name in an enclosing block; presumably a keyword or rebind the name in an enclosing block; presumably a keyword or
special syntax (x := 3) would make this possible. Given that this special syntax (x := 3) would make this possible. Given that this
would encourage the use of local variables to hold state that is would encourage the use of local variables to hold state that is
better stored in a class instance, it's not worth adding new better stored in a class instance, it's not worth adding new
syntax to make this possible (in Guido's opinion). syntax to make this possible (in Guido's opinion).
The proposed rules allow programmers to achieve the effect of The proposed rules allow programmers to achieve the effect of
rebinding, albeit awkwardly. The name that will be effectively rebinding, albeit awkwardly. The name that will be effectively
rebound by enclosed functions is bound to a container object. In rebound by enclosed functions is bound to a container object. In
place of assignment, the program uses modification of the place of assignment, the program uses modification of the
container to achieve the desired effect: container to achieve the desired effect::
def bank_account(initial_balance): def bank_account(initial_balance):
balance = [initial_balance] balance = [initial_balance]
@ -450,54 +470,57 @@ Rebinding names in enclosing scopes
return balance return balance
return deposit, withdraw return deposit, withdraw
Support for rebinding in nested scopes would make this code Support for rebinding in nested scopes would make this code
clearer. A class that defines deposit() and withdraw() methods clearer. A class that defines ``deposit()`` and ``withdraw()`` methods
and the balance as an instance variable would be clearer still. and the balance as an instance variable would be clearer still.
Since classes seem to achieve the same effect in a more Since classes seem to achieve the same effect in a more
straightforward manner, they are preferred. straightforward manner, they are preferred.
Implementation Implementation
==============
XXX Jeremy, is this still the case? XXX Jeremy, is this still the case?
The implementation for C Python uses flat closures [1]. Each def The implementation for C Python uses flat closures [1]_. Each def
or lambda expression that is executed will create a closure if the or lambda expression that is executed will create a closure if the
body of the function or any contained function has free body of the function or any contained function has free
variables. Using flat closures, the creation of closures is variables. Using flat closures, the creation of closures is
somewhat expensive but lookup is cheap. somewhat expensive but lookup is cheap.
The implementation adds several new opcodes and two new kinds of The implementation adds several new opcodes and two new kinds of
names in code objects. A variable can be either a cell variable names in code objects. A variable can be either a cell variable
or a free variable for a particular code object. A cell variable or a free variable for a particular code object. A cell variable
is referenced by containing scopes; as a result, the function is referenced by containing scopes; as a result, the function
where it is defined must allocate separate storage for it on each where it is defined must allocate separate storage for it on each
invocation. A free variable is referenced via a function's invocation. A free variable is referenced via a function's
closure. closure.
The choice of free closures was made based on three factors. The choice of free closures was made based on three factors.
First, nested functions are presumed to be used infrequently, First, nested functions are presumed to be used infrequently,
deeply nested (several levels of nesting) still less frequently. deeply nested (several levels of nesting) still less frequently.
Second, lookup of names in a nested scope should be fast. Second, lookup of names in a nested scope should be fast.
Third, the use of nested scopes, particularly where a function Third, the use of nested scopes, particularly where a function
that access an enclosing scope is returned, should not prevent that access an enclosing scope is returned, should not prevent
unreferenced objects from being reclaimed by the garbage unreferenced objects from being reclaimed by the garbage
collector. collector.
XXX Much more to say here XXX Much more to say here
References References
==========
[1] Luca Cardelli. Compiling a functional language. In Proc. of .. [1] Luca Cardelli. Compiling a functional language. In Proc. of
the 1984 ACM Conference on Lisp and Functional Programming, the 1984 ACM Conference on Lisp and Functional Programming,
pp. 208-217, Aug. 1984 pp. 208-217, Aug. 1984
http://citeseer.ist.psu.edu/cardelli84compiling.html http://citeseer.ist.psu.edu/cardelli84compiling.html
Copyright Copyright
=========
XXX XXX
..
Local Variables: Local Variables:
mode: indented-text mode: indented-text
indent-tabs-mode: nil indent-tabs-mode: nil
End: End: