371 lines
13 KiB
Plaintext
371 lines
13 KiB
Plaintext
PEP: 236
|
|
Title: Back to the __future__
|
|
Version: $Revision$
|
|
Last-Modified: $Date$
|
|
Author: Tim Peters <tim.peters@gmail.com>
|
|
Status: Final
|
|
Type: Standards Track
|
|
Content-Type: text/x-rst
|
|
Created: 26-Feb-2001
|
|
Python-Version: 2.1
|
|
Post-History: 26-Feb-2001
|
|
|
|
|
|
Motivation
|
|
==========
|
|
|
|
From time to time, Python makes an incompatible change to the advertised
|
|
semantics of core language constructs, or changes their accidental
|
|
(implementation-dependent) behavior in some way. While this is never done
|
|
capriciously, and is always done with the aim of improving the language over
|
|
the long term, over the short term it's contentious and disrupting.
|
|
|
|
:pep:`5`, Guidelines for Language Evolution suggests ways to ease the pain,
|
|
and this PEP introduces some machinery in support of that.
|
|
|
|
:pep:`227`, Statically Nested Scopes is the first application, and will be
|
|
used as an example here.
|
|
|
|
|
|
Intent
|
|
======
|
|
|
|
[Note: This is policy, and so should eventually move into :pep:`5`]
|
|
|
|
When an incompatible change to core language syntax or semantics is being
|
|
made:
|
|
|
|
1. The release C that introduces the change does not change the syntax or
|
|
semantics by default.
|
|
|
|
2. A future release R is identified in which the new syntax or semantics will
|
|
be enforced.
|
|
|
|
3. The mechanisms described in :pep:`230`, Warning Framework are used to
|
|
generate warnings, whenever possible, about constructs or operations whose
|
|
meaning may [1]_ change in release R.
|
|
|
|
4. The new future_statement (see below) can be explicitly included in a module
|
|
M to request that the code in module M use the new syntax or semantics in
|
|
the current release C.
|
|
|
|
So old code continues to work by default, for at least one release, although
|
|
it may start to generate new warning messages. Migration to the new syntax or
|
|
semantics can proceed during that time, using the future_statement to make
|
|
modules containing it act as if the new syntax or semantics were already being
|
|
enforced.
|
|
|
|
Note that there is no need to involve the future_statement machinery in new
|
|
features unless they can break existing code; fully backward- compatible
|
|
additions can-- and should --be introduced without a corresponding
|
|
future_statement.
|
|
|
|
|
|
Syntax
|
|
======
|
|
|
|
A future_statement is simply a from/import statement using the reserved module
|
|
name ``__future__``::
|
|
|
|
future_statement: "from" "__future__" "import" feature ["as" name]
|
|
(","feature ["as" name])*
|
|
|
|
feature: identifier
|
|
name: identifier
|
|
|
|
In addition, all future_statements must appear near the top of the module. The
|
|
only lines that can appear before a future_statement are:
|
|
|
|
+ The module docstring (if any).
|
|
+ Comments.
|
|
+ Blank lines.
|
|
+ Other future_statements.
|
|
|
|
Example::
|
|
|
|
"""This is a module docstring."""
|
|
|
|
# This is a comment, preceded by a blank line and followed by
|
|
# a future_statement.
|
|
from __future__ import nested_scopes
|
|
|
|
from math import sin
|
|
from __future__ import alabaster_weenoblobs # compile-time error!
|
|
# That was an error because preceded by a non-future_statement.
|
|
|
|
|
|
Semantics
|
|
=========
|
|
|
|
A future_statement is recognized and treated specially at compile time:
|
|
changes to the semantics of core constructs are often implemented by
|
|
generating different code. It may even be the case that a new feature
|
|
introduces new incompatible syntax (such as a new reserved word), in which
|
|
case the compiler may need to parse the module differently. Such decisions
|
|
cannot be pushed off until runtime.
|
|
|
|
For any given release, the compiler knows which feature names have been
|
|
defined, and raises a compile-time error if a future_statement contains a
|
|
feature not known to it [2]_.
|
|
|
|
The direct runtime semantics are the same as for any ``import`` statement:
|
|
there is a standard module ``__future__.py``, described later, and it will be
|
|
imported in the usual way at the time the future_statement is executed.
|
|
|
|
The *interesting* runtime semantics depend on the specific feature(s)
|
|
"imported" by the future_statement(s) appearing in the module.
|
|
|
|
Note that there is nothing special about the statement::
|
|
|
|
import __future__ [as name]
|
|
|
|
That is not a future_statement; it's an ordinary import statement, with no
|
|
special semantics or syntax restrictions.
|
|
|
|
|
|
Example
|
|
=======
|
|
|
|
Consider this code, in file scope.py::
|
|
|
|
x = 42
|
|
def f():
|
|
x = 666
|
|
def g():
|
|
print "x is", x
|
|
g()
|
|
f()
|
|
|
|
Under 2.0, it prints::
|
|
|
|
x is 42
|
|
|
|
Nested scopes (:pep:`227`) are being introduced in 2.1. But under 2.1, it still
|
|
prints::
|
|
|
|
x is 42
|
|
|
|
and also generates a warning.
|
|
|
|
In 2.2, and also in 2.1 *if* ``from __future__ import nested_scopes`` is
|
|
included at the top of ``scope.py``, it prints::
|
|
|
|
x is 666
|
|
|
|
|
|
Standard Module __future__.py
|
|
=============================
|
|
|
|
``Lib/__future__.py`` is a real module, and serves three purposes:
|
|
|
|
1. To avoid confusing existing tools that analyze import statements and expect
|
|
to find the modules they're importing.
|
|
|
|
2. To ensure that future_statements run under releases prior to 2.1 at least
|
|
yield runtime exceptions (the import of ``__future__`` will fail, because
|
|
there was no module of that name prior to 2.1).
|
|
|
|
3. To document when incompatible changes were introduced, and when they will
|
|
be-- or were --made mandatory. This is a form of executable documentation,
|
|
and can be inspected programmatically via importing ``__future__`` and
|
|
examining its contents.
|
|
|
|
Each statement in ``__future__.py`` is of the form::
|
|
|
|
FeatureName = "_Feature(" OptionalRelease "," MandatoryRelease ")"
|
|
|
|
where, normally, *OptionalRelease* < *MandatoryRelease*, and both are
|
|
5-tuples of the same form as ``sys.version_info``::
|
|
|
|
(PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int
|
|
PY_MINOR_VERSION, # the 1; an int
|
|
PY_MICRO_VERSION, # the 0; an int
|
|
PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string
|
|
PY_RELEASE_SERIAL # the 3; an int )
|
|
|
|
*OptionalRelease* records the first release in which::
|
|
|
|
from __future__ import FeatureName
|
|
|
|
was accepted.
|
|
|
|
In the case of *MandatoryReleases* that have not yet occurred,
|
|
*MandatoryRelease* predicts the release in which the feature will become part
|
|
of the language.
|
|
|
|
Else *MandatoryRelease* records when the feature became part of the language;
|
|
in releases at or after that, modules no longer need::
|
|
|
|
from __future__ import FeatureName
|
|
|
|
to use the feature in question, but may continue to use such imports.
|
|
|
|
*MandatoryRelease* may also be ``None``, meaning that a planned feature got
|
|
dropped.
|
|
|
|
Instances of ``class _Feature`` have two corresponding methods,
|
|
``.getOptionalRelease()`` and ``.getMandatoryRelease()``.
|
|
|
|
No feature line will ever be deleted from ``__future__.py``.
|
|
|
|
Example line::
|
|
|
|
nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "final", 0))
|
|
|
|
This means that::
|
|
|
|
from __future__ import nested_scopes
|
|
|
|
will work in all releases at or after 2.1b1, and that nested_scopes are
|
|
intended to be enforced starting in release 2.2.
|
|
|
|
|
|
Resolved Problem: Runtime Compilation
|
|
======================================
|
|
|
|
Several Python features can compile code during a module's runtime:
|
|
|
|
1. The ``exec`` statement.
|
|
2. The ``execfile()`` function.
|
|
3. The ``compile()`` function.
|
|
4. The ``eval()`` function.
|
|
5. The ``input()`` function.
|
|
|
|
Since a module M containing a future_statement naming feature F explicitly
|
|
requests that the current release act like a future release with respect to F,
|
|
any code compiled dynamically from text passed to one of these from within M
|
|
should probably also use the new syntax or semantics associated with F. The
|
|
2.1 release does behave this way.
|
|
|
|
This isn't always desired, though. For example, ``doctest.testmod(M)``
|
|
compiles examples taken from strings in M, and those examples should use M's
|
|
choices, not necessarily the doctest module's choices. In the 2.1 release,
|
|
this isn't possible, and no scheme has yet been suggested for working around
|
|
this. NOTE: :pep:`264` later addressed this in a flexible way, by adding
|
|
optional arguments to ``compile()``.
|
|
|
|
In any case, a future_statement appearing "near the top" (see Syntax above) of
|
|
text compiled dynamically by an ``exec``, ``execfile()`` or ``compile()``
|
|
applies to the code block generated, but has no further effect on the module
|
|
that executes such an ``exec``, ``execfile()`` or ``compile()``. This can't
|
|
be used to affect ``eval()`` or ``input()``, however, because they only allow
|
|
expression input, and a future_statement is not an expression.
|
|
|
|
|
|
Resolved Problem: Native Interactive Shells
|
|
============================================
|
|
|
|
There are two ways to get an interactive shell:
|
|
|
|
1. By invoking Python from a command line without a script argument.
|
|
|
|
2. By invoking Python from a command line with the ``-i`` switch and with a
|
|
script argument.
|
|
|
|
An interactive shell can be seen as an extreme case of runtime compilation
|
|
(see above): in effect, each statement typed at an interactive shell prompt
|
|
runs a new instance of ``exec``, ``compile()`` or ``execfile()``. A
|
|
future_statement typed at an interactive shell applies to the rest of the
|
|
shell session's life, as if the future_statement had appeared at the top of a
|
|
module.
|
|
|
|
|
|
Resolved Problem: Simulated Interactive Shells
|
|
===============================================
|
|
|
|
Interactive shells "built by hand" (by tools such as IDLE and the Emacs
|
|
Python-mode) should behave like native interactive shells (see above).
|
|
However, the machinery used internally by native interactive shells has not
|
|
been exposed, and there isn't a clear way for tools building their own
|
|
interactive shells to achieve the desired behavior.
|
|
|
|
NOTE: :pep:`264` later addressed this, by adding intelligence to the standard
|
|
``codeop.py``. Simulated shells that don't use the standard library shell
|
|
helpers can get a similar effect by exploiting the new optional arguments to
|
|
``compile()`` added by :pep:`264`.
|
|
|
|
|
|
Questions and Answers
|
|
=====================
|
|
|
|
What about a "from __past__" version, to get back *old* behavior?
|
|
-----------------------------------------------------------------
|
|
|
|
Outside the scope of this PEP. Seems unlikely to the author, though. Write a
|
|
PEP if you want to pursue it.
|
|
|
|
What about incompatibilities due to changes in the Python virtual machine?
|
|
--------------------------------------------------------------------------
|
|
|
|
Outside the scope of this PEP, although :pep:`5` suggests a grace period
|
|
there too, and the future_statement may also have a role to play there.
|
|
|
|
What about incompatibilities due to changes in Python's C API?
|
|
--------------------------------------------------------------
|
|
|
|
Outside the scope of this PEP.
|
|
|
|
I want to wrap future_statements in try/except blocks, so I can use different code depending on which version of Python I'm running. Why can't I?
|
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
Sorry! ``try/except`` is a runtime feature; future_statements are primarily
|
|
compile-time gimmicks, and your ``try/except`` happens long after the compiler
|
|
is done. That is, by the time you do ``try/except``, the semantics in effect
|
|
for the module are already a done deal. Since the ``try/except`` wouldn't
|
|
accomplish what it *looks* like it should accomplish, it's simply not allowed.
|
|
We also want to keep these special statements very easy to find and to
|
|
recognize.
|
|
|
|
Note that you *can* import ``__future__`` directly, and use the information in
|
|
it, along with ``sys.version_info``, to figure out where the release you're
|
|
running under stands in relation to a given feature's status.
|
|
|
|
Going back to the nested_scopes example, what if release 2.2 comes along and I still haven't changed my code? How can I keep the 2.1 behavior then?
|
|
----------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
By continuing to use 2.1, and not moving to 2.2 until you do change your
|
|
code. The purpose of future_statement is to make life easier for people who
|
|
keep current with the latest release in a timely fashion. We don't hate you
|
|
if you don't, but your problems are much harder to solve, and somebody with
|
|
those problems will need to write a PEP addressing them. future_statement is
|
|
aimed at a different audience.
|
|
|
|
Overloading ``import`` sucks. Why not introduce a new statement for this?
|
|
--------------------------------------------------------------------------
|
|
|
|
Like maybe ``lambda lambda nested_scopes``? That is, unless we introduce a
|
|
new keyword, we can't introduce an entirely new statement. But if we
|
|
introduce a new keyword, that in itself would break old code. That would be
|
|
too ironic to bear. Yes, overloading ``import`` does suck, but not as
|
|
energetically as the alternatives -- as is, future_statements are 100%
|
|
backward compatible.
|
|
|
|
|
|
Copyright
|
|
=========
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
References and Footnotes
|
|
========================
|
|
|
|
.. [1] Note that this is *may* and not *will*: better safe than sorry. Of course
|
|
spurious warnings won't be generated when avoidable with reasonable cost.
|
|
|
|
.. [2] This ensures that a future_statement run under a release prior to the
|
|
first one in which a given feature is known (but >= 2.1) will raise a
|
|
compile-time error rather than silently do a wrong thing. If transported
|
|
to a release prior to 2.1, a runtime error will be raised because of the
|
|
failure to import ``__future__`` (no such module existed in the standard
|
|
distribution before the 2.1 release, and the double underscores make it a
|
|
reserved name).
|
|
|
|
|
|
|
|
..
|
|
Local Variables:
|
|
mode: indented-text
|
|
indent-tabs-mode: nil
|
|
End:
|