Clarify rules for names defined in class scope. (Classes hide names
was a bad label.) Add note about how to implement flat closures using an extra level of indirection.
This commit is contained in:
parent
0bb1267cae
commit
4be092d93e
52
pep-0227.txt
52
pep-0227.txt
|
@ -56,11 +56,9 @@ Specification
|
|||
|
||||
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. A region is visible from a
|
||||
block is all enclosing blocks are introduced by function
|
||||
defintions. (Note: If a region is contained within a class
|
||||
definition, the name bindings that occur in the class block are
|
||||
not visible to enclosed functions.)
|
||||
the nearest enclosing function region. (Note: If a region is
|
||||
contained within a class definition, the name bindings that occur
|
||||
in the class block are not visible to enclosed functions.)
|
||||
|
||||
A class definition is an executable statement that may uses and
|
||||
definitions of names. These references follow the normal rules
|
||||
|
@ -111,19 +109,19 @@ Discussion
|
|||
name resolution rules are typical for statically scoped languages,
|
||||
with three primary exceptions:
|
||||
|
||||
- Class definitions hide names.
|
||||
- Names in class scope are not accessible.
|
||||
- The global statement short-circuits the normal rules.
|
||||
- Variables are not declared.
|
||||
|
||||
Class definitions hide names. Names are resolved in the innermost
|
||||
enclosing function scope. If a class defintion occurs in a chain
|
||||
of nested scopes, the resolution process skips class definitions.
|
||||
This rule prevents odd interactions between class attributes and
|
||||
local variable access. If a name binding operation occurs in a
|
||||
class defintion, it creates an attribute on the resulting class
|
||||
object. To access this variable in a method, or in a function
|
||||
nested within a method, an attribute reference must be used,
|
||||
either via self or via the class name.
|
||||
Names in class scope are not accessible. Names are resolved in
|
||||
the innermost enclosing function scope. If a class defintion
|
||||
occurs in a chain of nested scopes, the resolution process skips
|
||||
class definitions. This rule prevents odd interactions between
|
||||
class attributes and local variable access. If a name binding
|
||||
operation occurs in a class defintion, it creates an attribute on
|
||||
the resulting class object. To access this variable in a method,
|
||||
or in a function nested within a method, an attribute reference
|
||||
must be used, either via self or via the class name.
|
||||
|
||||
An alternative would have been to allow name binding in class
|
||||
scope to behave exactly like name binding in function scope. This
|
||||
|
@ -295,17 +293,17 @@ Implementation
|
|||
code and the environment in which to resolve free variables.
|
||||
|
||||
There are a variety of implementation alternatives for closures.
|
||||
One possibility is to use a static link from a nested function to
|
||||
its enclosing environment. This implementation requires several
|
||||
links to be followed if there is more than one level of nesting
|
||||
and keeps many garbage objects alive longer than necessary.
|
||||
Two typical ones are nested closures and flat closures. Nested
|
||||
closures use a static link from a nested function to its enclosing
|
||||
environment. This implementation requires several links to be
|
||||
followed if there is more than one level of nesting and keeps many
|
||||
garbage objects alive longer than necessary.
|
||||
|
||||
One fairly simple implementation approach would be to implement
|
||||
the default argument hack currently used for lambda support. Each
|
||||
function object would have a func_env slot that holds a tuple of
|
||||
free variable bindings. The code inside the function would use
|
||||
LOAD_ENV to access these bindings rather than the typical
|
||||
LOAD_FAST.
|
||||
Flat closures are roughly similar to the default argument hack
|
||||
currently used for lambda support. Each function object would
|
||||
have a func_env slot that holds a tuple of free variable bindings.
|
||||
The code inside the function would use LOAD_ENV to access these
|
||||
bindings rather than the typical LOAD_FAST.
|
||||
|
||||
The problem with this approach is that rebindings are not visible
|
||||
to the nested function. Consider the following example:
|
||||
|
@ -329,6 +327,10 @@ Implementation
|
|||
definition time. This is the default argument hack, but not
|
||||
actual name resolution based on statically nested scopes.
|
||||
|
||||
To support shared visibility of updates, it will be necessary to
|
||||
have a tuple of cells that contain references to variables. The
|
||||
extra level of indirection should allow updates to be shared.
|
||||
|
||||
It is not clear whether the current 1-pass Python compiler can
|
||||
determine which references are to globals and which are references
|
||||
to enclosing scopes. It may be possible to make minimal changes
|
||||
|
|
Loading…
Reference in New Issue