Update to reflect pending __future__ PEP, availability in 2.1 and 2.2,

and warnings.

Various bugs reported by Aahz Maruch.
This commit is contained in:
Jeremy Hylton 2001-02-26 20:08:05 +00:00
parent 910d1b4561
commit 9b6d9b4453
1 changed files with 104 additions and 23 deletions

View File

@ -26,13 +26,18 @@ Abstract
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 Python 2.0 definition specifies exactly Python functions. The new name resolution semantics will take
three namespaces to check for each name -- the local namespace, effect with Python 2.2. These semantics will also be available in
the global namespace, and the builtin namespace. According to Python 2.1 by adding "from __future__ import nested_scopes" to the
this defintion, if a function A is defined within a function B, top of a module.
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 The Python 2.0 definition specifies exactly three namespaces to
contains a name binding that hides the binding in B). check for each name -- 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).
The specification introduces rules for lexical scoping that are The 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
@ -62,11 +67,19 @@ Introduction
in crude terms, implements the default argument approach 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
behave differently than they did under Python 2.0. In some cases,
programs will fail to compile. In other cases, names that were
previously resolved using the global namespace will be resolved
using the local namespace of an enclosing function. In Python
2.1, warnings will be issued for all program statement that will
behave 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 defintion, 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
@ -91,7 +104,8 @@ Specification
module containing the code block, and the builtin namespace, the module containing the code block, and the builtin namespace, the
namespace of the module __builtin__. The global namespace is namespace of the module __builtin__. The global namespace is
searched first. If the name is not found there, the builtin searched first. If the name is not found there, the builtin
namespace is searched. namespace is searched. The global statement 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
@ -108,7 +122,7 @@ Specification
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 defintion: def name ... Function definition: def name ...
Class definition: class name ... Class definition: class name ...
Assignment statement: name = ... Assignment statement: name = ...
Import statement: import name, import module as name, Import statement: import name, import module as name,
@ -126,16 +140,24 @@ Specification
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 wildcard 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 explicit 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
global name or a standard builtin name and the function contains a
nested function scope that references the name, the compiler will
issue a warning. The name resolution rules will result in
different bindings under Python 2.0 than under Python 2.2. The
warning indicates that the program may not run correctly with all
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
@ -148,11 +170,11 @@ Discussion
- 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 defintion 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 defintion, 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.
@ -167,7 +189,7 @@ Discussion
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's behavior is preserved for backwards does for Python 2.0. Its behavior is preserved for backwards
compatibility. It is also noteworthy because it allows name compatibility. 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).
@ -233,8 +255,8 @@ Examples
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
AttributeError: _private AttributeError: _private
An example from Tim Peters of the potential pitfalls of nested scopes An example from Tim Peters demonstrates the potential pitfalls of
in the absence of declarations: nested scopes in the absence of declarations:
i = 6 i = 6
def f(x): def f(x):
@ -257,7 +279,7 @@ 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.
@ -285,9 +307,9 @@ Backwards compatibility
To address this problem, which is unlikely to occur often, a To address this problem, which is unlikely to occur often, a
static analysis tool that detects affected code will be written. static analysis tool that detects affected code will be written.
The detection problem is straightfoward. The detection problem is straightforward.
The other compatibility problem is casued 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:
@ -300,7 +322,7 @@ Backwards compatibility
... ...
At compile-time, the compiler cannot tell whether an exec that At compile-time, the compiler cannot tell whether an exec that
operators 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().
@ -318,7 +340,7 @@ Backwards compatibility
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 problemtatic and the exact meaning Since each interpretation is problematic and the exact meaning
ambiguous, the compiler raises an exception. ambiguous, the compiler raises an exception.
A brief review of three Python projects (the standard library, A brief review of three Python projects (the standard library,
@ -332,6 +354,12 @@ Backwards compatibility
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
The implementation causes several Python C API functions to
change, including PyCode_New(). As a result, C extensions may
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
@ -344,6 +372,49 @@ locals() / vars()
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
The compiler will issue warnings in Python 2.1 to help identify
programs that may not compile or run correctly under future
versions of Python. Under Python 2.2 or Python 2.1 if the
nested_scopes future statement is used, which are collectively
referred to as "future semantics" in this section, the compiler
will issue SyntaxErrors in some cases.
The warnings typically apply when a function that contains a
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
function that contains a nested function (G) with a free variable
(len). The label "free-in-nested" will be used to describe these
functions.
import * used in function scope
The language reference specifies that import * may only occur
in a module scope. (Sec. 6.11) The implementation of C
Python has supported import * at the function scope.
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 raise a SyntaxError.
bare exec in function scope
The exec statement allows two optional expressions following
the keyword "in" that specify the namespaces used for locals
and globals. An exec statement that omits both of these
namespaces is a bare exec.
If a bare exec is used in the body of a free-in-nested
function, the compiler will issue a warning. Under future
semantics, the compiler will raise a SyntaxError.
local shadows global
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
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
@ -390,7 +461,17 @@ Implementation
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 reference via a function's closure. invocation. A free variable is referenced via a function's
closure.
The choice of free closures was made based on three factors.
First, nested functions are presumed to be used infrequently,
deeply nested (several levels of nesting) still less frequently.
Second, lookup of names in a nested scope should be fast.
Third, the use of nested scopes, particularly where a function
that access an enclosing scope is returned, should not prevent
unreferenced objects from being reclaimed by the garbage
collector.
XXX Much more to say here XXX Much more to say here