added PEPs 359 (The "make Statement) and 3002 (Procedure for Backwards-Incompatible Changes) by Steven Bethard
This commit is contained in:
parent
5d38f6aa3a
commit
7c39299824
|
@ -45,6 +45,7 @@ Index by Category
|
||||||
P 347 Migrating the Python CVS to Subversion von Löwis
|
P 347 Migrating the Python CVS to Subversion von Löwis
|
||||||
P 3000 Python 3000 GvR
|
P 3000 Python 3000 GvR
|
||||||
P 3001 Reviewing and improving stdlib modules Brandl
|
P 3001 Reviewing and improving stdlib modules Brandl
|
||||||
|
P 3002 Procedure for Backwards-Incompatible Changes Bethard
|
||||||
I 3099 Things that will Not Change in Python 3000 Brandl
|
I 3099 Things that will Not Change in Python 3000 Brandl
|
||||||
|
|
||||||
Other Informational PEPs
|
Other Informational PEPs
|
||||||
|
@ -102,6 +103,7 @@ Index by Category
|
||||||
S 354 Enumerations in Python Finney
|
S 354 Enumerations in Python Finney
|
||||||
S 355 Path - Object oriented filesystem paths Lindqvist
|
S 355 Path - Object oriented filesystem paths Lindqvist
|
||||||
S 358 The "bytes" Object Schemenauer
|
S 358 The "bytes" Object Schemenauer
|
||||||
|
S 359 The "make" Statement Bethard
|
||||||
S 754 IEEE 754 Floating Point Special Values Warnes
|
S 754 IEEE 754 Floating Point Special Values Warnes
|
||||||
|
|
||||||
Finished PEPs (done, implemented in Subversion)
|
Finished PEPs (done, implemented in Subversion)
|
||||||
|
@ -415,10 +417,12 @@ Numerical Index
|
||||||
I 356 Python 2.5 Release Schedule Norwitz, et al
|
I 356 Python 2.5 Release Schedule Norwitz, et al
|
||||||
SF 357 Allowing Any Object to be Used for Slicing Oliphant
|
SF 357 Allowing Any Object to be Used for Slicing Oliphant
|
||||||
S 358 The "bytes" Object Schemenauer
|
S 358 The "bytes" Object Schemenauer
|
||||||
|
S 359 The "make" Statement Bethard
|
||||||
SR 666 Reject Foolish Indentation Creighton
|
SR 666 Reject Foolish Indentation Creighton
|
||||||
S 754 IEEE 754 Floating Point Special Values Warnes
|
S 754 IEEE 754 Floating Point Special Values Warnes
|
||||||
P 3000 Python 3000 GvR
|
P 3000 Python 3000 GvR
|
||||||
P 3001 Reviewing and improving stdlib modules Brandl
|
P 3001 Reviewing and improving stdlib modules Brandl
|
||||||
|
P 3002 Procedure for Backwards-Incompatible Changes Bethard
|
||||||
I 3099 Things that will Not Change in Python 3000 Brandl
|
I 3099 Things that will Not Change in Python 3000 Brandl
|
||||||
I 3100 Python 3.0 Plans Kuchling, Cannon
|
I 3100 Python 3.0 Plans Kuchling, Cannon
|
||||||
|
|
||||||
|
@ -449,6 +453,7 @@ Owners
|
||||||
Batista, Facundo facundo@taniquetil.com.ar
|
Batista, Facundo facundo@taniquetil.com.ar
|
||||||
Baxter, Anthony anthony@interlink.com.au
|
Baxter, Anthony anthony@interlink.com.au
|
||||||
Bellman, Thomas bellman+pep-divmod@lysator.liu.se
|
Bellman, Thomas bellman+pep-divmod@lysator.liu.se
|
||||||
|
Bethard, Steven steven.bethard@gmail.com
|
||||||
Brandl, Georg g.brandl@gmx.net
|
Brandl, Georg g.brandl@gmx.net
|
||||||
Cannon, Brett brett@python.org
|
Cannon, Brett brett@python.org
|
||||||
Carlson, Josiah jcarlson@uci.edu
|
Carlson, Josiah jcarlson@uci.edu
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
PEP: 359
|
||||||
|
Title: The "make" Statement
|
||||||
|
Version: $Revision$
|
||||||
|
Last-Modified: $Date$
|
||||||
|
Author: Steven Bethard <steven.bethard@gmail.com>
|
||||||
|
Status: Draft
|
||||||
|
Type: Standards Track
|
||||||
|
Content-Type: text/x-rst
|
||||||
|
Created: 05-Apr-2006
|
||||||
|
Python-Version: 2.6
|
||||||
|
Post-History: 05-Apr-2006, 06-Apr-2006
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
This PEP proposes a generalization of the class-declaration syntax,
|
||||||
|
the ``make`` statement. The proposed syntax and semantics parallel
|
||||||
|
the syntax for class definition, and so::
|
||||||
|
|
||||||
|
make <callable> <name> <tuple>:
|
||||||
|
<block>
|
||||||
|
|
||||||
|
is translated into the assignment::
|
||||||
|
|
||||||
|
<name> = <callable>("<name>", <tuple>, <namespace>)
|
||||||
|
|
||||||
|
where ``<namespace>`` is the dict created by executing ``<block>``.
|
||||||
|
The PEP is based on a suggestion [1]_ from Michele Simionato on the
|
||||||
|
python-dev list.
|
||||||
|
|
||||||
|
|
||||||
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
|
Class statements provide two nice facilities to Python:
|
||||||
|
|
||||||
|
(1) They are the standard Python means of creating a namespace. All
|
||||||
|
statements within a class body are executed, and the resulting
|
||||||
|
local name bindings are passed as a dict to the metaclass.
|
||||||
|
|
||||||
|
(2) They encourage DRY (don't repeat yourself) by allowing the class
|
||||||
|
being created to know the name it is being assigned.
|
||||||
|
|
||||||
|
Thus in a simple class statement like::
|
||||||
|
|
||||||
|
class C(object):
|
||||||
|
x = 1
|
||||||
|
def foo(self):
|
||||||
|
return 'bar'
|
||||||
|
|
||||||
|
the metaclass (``type``) gets called with something like::
|
||||||
|
|
||||||
|
C = type('C', (object,), {'x':1, 'foo':<function foo at ...>})
|
||||||
|
|
||||||
|
The class statement is just syntactic sugar for the above assignment
|
||||||
|
statement, but clearly a very useful sort of syntactic sugar. It
|
||||||
|
avoids not only the repetition of ``C``, but also simplifies the
|
||||||
|
creation of the dict by allowing it to be expressed as a series of
|
||||||
|
statements.
|
||||||
|
|
||||||
|
Historically, type instances (a.k.a. class objects) have been the only
|
||||||
|
objects blessed with this sort of syntactic support. But other sorts
|
||||||
|
of objects could benefit from such support. For example, property
|
||||||
|
objects take three function arguments, but because the property type
|
||||||
|
cannot be passed a namespace, these functions, though relevant only to
|
||||||
|
the property, must be declared before it and then passed as arguments
|
||||||
|
to the property call, e.g.::
|
||||||
|
|
||||||
|
class C(object):
|
||||||
|
...
|
||||||
|
def get_x(self):
|
||||||
|
...
|
||||||
|
def set_x(self):
|
||||||
|
...
|
||||||
|
x = property(get_x, set_x, ...)
|
||||||
|
|
||||||
|
There have been a few recipes [2]_ trying to work around this
|
||||||
|
behavior, but with the new make statement (and an appropriate
|
||||||
|
definition of property), the getter and setter functions can be
|
||||||
|
defined in the property's namespace like::
|
||||||
|
|
||||||
|
class C(object):
|
||||||
|
...
|
||||||
|
make property x:
|
||||||
|
def get(self):
|
||||||
|
...
|
||||||
|
def set(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
The definition of such a property callable could be as simple as::
|
||||||
|
|
||||||
|
def property(name, args, namespace):
|
||||||
|
fget = namespace.get('get')
|
||||||
|
fset = namespace.get('set')
|
||||||
|
fdel = namespace.get('delete')
|
||||||
|
doc = namespace.get('__doc__')
|
||||||
|
return __builtin__.property(fget, fset, fdel, doc)
|
||||||
|
|
||||||
|
Of course, properties are only one of the many possible uses of the
|
||||||
|
make statement. The make statement is useful in essentially any
|
||||||
|
situation where a name is associated with a namespace. So, for
|
||||||
|
example, namespaces could be created as simply as::
|
||||||
|
|
||||||
|
make namespace ns:
|
||||||
|
"""This creates a namespace named ns with a badger attribute
|
||||||
|
and a spam function"""
|
||||||
|
|
||||||
|
badger = 42
|
||||||
|
|
||||||
|
def spam():
|
||||||
|
...
|
||||||
|
|
||||||
|
And if Python acquires interfaces, given an appropriately defined
|
||||||
|
``interface`` callable, the make statement can support interface
|
||||||
|
creation through the syntax::
|
||||||
|
|
||||||
|
make interface C(...):
|
||||||
|
...
|
||||||
|
|
||||||
|
This would mean that interface systems like that of Zope would no
|
||||||
|
longer have to abuse the class syntax to create proper interface
|
||||||
|
instances.
|
||||||
|
|
||||||
|
|
||||||
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
|
Python will translate a make statement::
|
||||||
|
|
||||||
|
make <callable> <name> <tuple>:
|
||||||
|
<block>
|
||||||
|
|
||||||
|
into the assignment::
|
||||||
|
|
||||||
|
<name> = <callable>("<name>", <tuple>, <namespace>)
|
||||||
|
|
||||||
|
where ``<namespace>`` is the dict created by executing ``<block>``.
|
||||||
|
The ``<tuple>`` expression is optional; if not present, an empty tuple
|
||||||
|
will be assumed.
|
||||||
|
|
||||||
|
A patch is available implementing these semantics [3]_.
|
||||||
|
|
||||||
|
The make statement introduces a new keyword, ``make``. Thus in Python
|
||||||
|
2.6, the make statement will have to be enabled using ``from
|
||||||
|
__future__ import make_statement``.
|
||||||
|
|
||||||
|
|
||||||
|
Open Issues
|
||||||
|
===========
|
||||||
|
|
||||||
|
Does the ``make`` keyword break too much code? Originally, the make
|
||||||
|
statement used the keyword ``create`` (a suggestion due to Nick
|
||||||
|
Coghlan). However, investigations into the standard library [4]_ and
|
||||||
|
Zope+Plone code [5]_ revealed that ``create`` would break a lot more
|
||||||
|
code, so ``make`` was adopted as the keyword instead. However, there
|
||||||
|
are still a few instances where ``make`` would break code. Is there a
|
||||||
|
better keyword for the statement?
|
||||||
|
|
||||||
|
**********
|
||||||
|
|
||||||
|
Currently, there are not many functions which have the signature
|
||||||
|
``(name, args, kwargs)``. That means that something like::
|
||||||
|
|
||||||
|
make dict params:
|
||||||
|
x = 1
|
||||||
|
y = 2
|
||||||
|
|
||||||
|
is currently impossible because the dict constructor has a different
|
||||||
|
signature. Does this sort of thing need to be supported? One
|
||||||
|
suggestion, by Carl Banks, would be to add a ``__make__`` magic method
|
||||||
|
that would be called before ``__call__``. For types, the ``__make__``
|
||||||
|
method would be identical to ``__call__`` (and thus unnecessary), but
|
||||||
|
dicts could support the make statement by defining a ``__make__``
|
||||||
|
method on the dict type that looks something like::
|
||||||
|
|
||||||
|
def __make__(cls, name, args, kwargs):
|
||||||
|
return cls(**kwargs)
|
||||||
|
|
||||||
|
Of course, rather than adding another magic method, the dict type
|
||||||
|
could just grow a classmethod something like ``dict.fromblock`` that
|
||||||
|
could be used like::
|
||||||
|
|
||||||
|
make dict.fromblock params:
|
||||||
|
x = 1
|
||||||
|
y = 2
|
||||||
|
|
||||||
|
|
||||||
|
Optional Extensions
|
||||||
|
===================
|
||||||
|
|
||||||
|
Remove the make keyword
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
It might be possible to remove the make keyword so that such
|
||||||
|
statements would begin with the callable being called, e.g.::
|
||||||
|
|
||||||
|
namespace ns:
|
||||||
|
badger = 42
|
||||||
|
def spam():
|
||||||
|
...
|
||||||
|
|
||||||
|
interface C(...):
|
||||||
|
...
|
||||||
|
|
||||||
|
However, almost all other Python statements begin with a keyword, and
|
||||||
|
removing the keyword would make it harder to look up this construct in
|
||||||
|
the documentation. Additionally, this would add some complexity in
|
||||||
|
the grammar and so far I (Steven Bethard) have not been able to
|
||||||
|
implement the feature without the keyword.
|
||||||
|
|
||||||
|
|
||||||
|
Removing __metaclass__ in Python 3000
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
As a side-effect of its generality, the make statement mostly
|
||||||
|
eliminates the need for the ``__metaclass__`` attribute in class
|
||||||
|
objects. Thus in Python 3000, instead of::
|
||||||
|
|
||||||
|
class <name> <bases-tuple>:
|
||||||
|
__metaclass__ = <metaclass>
|
||||||
|
<block>
|
||||||
|
|
||||||
|
metaclasses could be supported by using the metaclass as the callable
|
||||||
|
in a make statement::
|
||||||
|
|
||||||
|
make <metaclass> <name> <bases-tuple>:
|
||||||
|
<block>
|
||||||
|
|
||||||
|
Removing the ``__metaclass__`` hook would simplify the BUILD_CLASS
|
||||||
|
opcode a bit.
|
||||||
|
|
||||||
|
|
||||||
|
Removing class statements in Python 3000
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
In the most extreme application of make statements, the class
|
||||||
|
statement itself could be deprecated in favor of ``make type``
|
||||||
|
statements.
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. [1] Michele Simionato's original suggestion
|
||||||
|
(http://mail.python.org/pipermail/python-dev/2005-October/057435.html)
|
||||||
|
|
||||||
|
.. [2] Namespace-based property recipe
|
||||||
|
(http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442418)
|
||||||
|
|
||||||
|
.. [3] Make Statement patch
|
||||||
|
(http://ucsu.colorado.edu/~bethard/py/make_statement.patch)
|
||||||
|
|
||||||
|
.. [4] Instances of create in the stdlib
|
||||||
|
(http://mail.python.org/pipermail/python-list/2006-April/335159.html)
|
||||||
|
|
||||||
|
.. [5] Instances of create in Zope+Plone
|
||||||
|
(http://mail.python.org/pipermail/python-list/2006-April/335284.html)
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: utf-8
|
||||||
|
End:
|
|
@ -0,0 +1,164 @@
|
||||||
|
PEP: 3002
|
||||||
|
Title: Procedure for Backwards-Incompatible Changes
|
||||||
|
Version: $Revision$
|
||||||
|
Last-Modified: $Date$
|
||||||
|
Author: Steven Bethard <steven.bethard@gmail.com>
|
||||||
|
Status: Draft
|
||||||
|
Type: Process
|
||||||
|
Content-Type: text/x-rst
|
||||||
|
Created: 03-Mar-2006
|
||||||
|
Post-History: 03-Mar-2006
|
||||||
|
|
||||||
|
|
||||||
|
Abstract
|
||||||
|
========
|
||||||
|
|
||||||
|
This PEP describes the procedure for changes to Python that are
|
||||||
|
backwards-incompatible between the Python 2.X series and Python 3000.
|
||||||
|
All such changes must be documented by an appropriate Python 3000 PEP
|
||||||
|
and must be accompanied by code that can identify when pieces of
|
||||||
|
Python 2.X code may be problematic in Python 3000.
|
||||||
|
|
||||||
|
|
||||||
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
|
Python 3000 will introduce a number of backwards-incompatible changes
|
||||||
|
to Python, mainly to streamline the language and to remove some
|
||||||
|
previous design mistakes. But Python 3000 is not intended to be a new
|
||||||
|
and completely different language from the Python 2.X series, and it
|
||||||
|
is expected that much of the Python user community will make the
|
||||||
|
transition to Python 3000 when it becomes available.
|
||||||
|
|
||||||
|
To encourage this transition, it is crucial to provide a clear and
|
||||||
|
complete guide on how to upgrade Python 2.X code to Python 3000 code.
|
||||||
|
Thus, for any backwards-incompatible change, two things are required:
|
||||||
|
|
||||||
|
* An official Python Enhancement Proposal (PEP)
|
||||||
|
* Code that can identify pieces of Python 2.X code that may be
|
||||||
|
problematic in Python 3000
|
||||||
|
|
||||||
|
|
||||||
|
Python Enchancement Proposals
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Every backwards-incompatible change must be accompanied by a PEP.
|
||||||
|
This PEP should follow the usual PEP guidelines and explain the
|
||||||
|
purpose and reasoning behind the backwards incompatible change. In
|
||||||
|
addition to the usual PEP sections, all PEPs proposing
|
||||||
|
backwards-incompatible changes must include an additional section:
|
||||||
|
Compatibility Issues. This section should describe what is backwards
|
||||||
|
incompatible about the proposed change to Python, and the major sorts
|
||||||
|
of breakage to be expected.
|
||||||
|
|
||||||
|
While PEPs must still be evaluated on a case-by-case basis, a PEP may
|
||||||
|
be inappropriate for Python 3000 if its Compatibility Issues section
|
||||||
|
implies any of the following:
|
||||||
|
|
||||||
|
* Most or all instances of a Python 2.X construct are incorrect in
|
||||||
|
Python 3000, and most or all instances of the Python 3000 construct
|
||||||
|
are incorrect in Python 2.X.
|
||||||
|
|
||||||
|
So for example, changing the meaning of the for-loop else-clause
|
||||||
|
from "executed when the loop was not broken out of" to "executed
|
||||||
|
when the loop had zero iterations" would mean that all Python 2.X
|
||||||
|
for-loop else-clauses would be broken, and there would be no way to
|
||||||
|
use a for-loop else-clause in a Python-3000-appropriate manner.
|
||||||
|
Thus a PEP for such an idea would likely be rejected.
|
||||||
|
|
||||||
|
* Many instances of a Python 2.X construct are incorrect in Python
|
||||||
|
3000 and the PEP fails to demonstrate real-world use-cases for the
|
||||||
|
changes.
|
||||||
|
|
||||||
|
Backwards incompatible changes are allowed in Python 3000, but not
|
||||||
|
to excess. A PEP that proposes backwards-incompatible changes
|
||||||
|
should provide good examples of code that visibly benefits from the
|
||||||
|
changes.
|
||||||
|
|
||||||
|
PEP-writing is time-consuming, so when a number of
|
||||||
|
backwards-incompatible changes are closely related, they should be
|
||||||
|
proposed in the same PEP. Such PEPs will likely have longer
|
||||||
|
Compatibility Issues sections however, since they must now describe
|
||||||
|
the sorts of breakage expected from *all* the proposed changes.
|
||||||
|
|
||||||
|
|
||||||
|
Identifying Problematic Code
|
||||||
|
============================
|
||||||
|
|
||||||
|
In addition to the PEP requirement, backwards incompatible changes to
|
||||||
|
Python must also be accompanied by code that can identify pieces of
|
||||||
|
Python 2.X code that may be problematic in Python 3.0.
|
||||||
|
|
||||||
|
This PEP proposes to house this code in tools/scripts/python3warn.py.
|
||||||
|
Thus PEPs for backwards incompatible changes should include a patch to
|
||||||
|
this file that produces the appropriate warnings. Code in
|
||||||
|
python3warn.py should be written to the latest version of Python 2.X
|
||||||
|
(not Python 3000) so that Python 2.X users will be able to run the
|
||||||
|
program without having Python 3000 installed.
|
||||||
|
|
||||||
|
Currently, it seems too stringent to require that the code in
|
||||||
|
python3warn.py identify all changes perfectly. Thus it is permissable
|
||||||
|
if a backwards-incompatible PEP's python3warn.py code produces a
|
||||||
|
number of false-positives (warning that a piece of code might be
|
||||||
|
invalid in Python 3000 when it's actually still okay). However,
|
||||||
|
false-negatives (not issuing a warning for code that will do the
|
||||||
|
wrong thing in Python 3000) should be avoided whenever possible --
|
||||||
|
users of python3warn.py should be reasonably confident that they have
|
||||||
|
been warned about the vast majority of incompatibilities.
|
||||||
|
|
||||||
|
So for example, a PEP proposing that ``dict.items()`` be modified to
|
||||||
|
return an iterator instead of a list might add code like the following
|
||||||
|
to python3warn.py::
|
||||||
|
|
||||||
|
items_in_for = re.compile(r'for\s+\w+\s+in\s+\w+\.items\(\):')
|
||||||
|
...
|
||||||
|
for i, line in enumerate(file_lines):
|
||||||
|
...
|
||||||
|
if '.items()' in line and not items_in_for.search(line):
|
||||||
|
message = 'dict.items() call may expect list at line %i'
|
||||||
|
warnings.warn(message % i)
|
||||||
|
|
||||||
|
This would issue a warning any time a ``.items()`` method was called
|
||||||
|
and not immediately iterated over in a for-loop. Clearly this will
|
||||||
|
issue a number of false-positive warnings (e.g. ``d2 =
|
||||||
|
dict(d.items())``), but the number of false-negative warnings should
|
||||||
|
be relatively low.
|
||||||
|
|
||||||
|
|
||||||
|
Optional Extensions
|
||||||
|
===================
|
||||||
|
|
||||||
|
Instead of the python3warn.py script, a branch of Python 3000 could be
|
||||||
|
maintained that added warnings at all the appropriate points in the
|
||||||
|
code-base. PEPs proposing backwards-incompatible changes would then
|
||||||
|
provide patches to the Python-3000-warn branch instead of to
|
||||||
|
python3warn.py. With such a branch, the warnings issued could be
|
||||||
|
near-perfect and Python users could be confident that their code was
|
||||||
|
correct Python 3000 code by first running it on the Python-3000-warn
|
||||||
|
branch and fixing all the warnings.
|
||||||
|
|
||||||
|
At the moment, however, this PEP opts for the weaker measure
|
||||||
|
(python3warn.py) as it is expected that maintaining a Python-3000-warn
|
||||||
|
branch will be too much of a time drain.
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
TBD
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
..
|
||||||
|
Local Variables:
|
||||||
|
mode: indented-text
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
sentence-end-double-space: t
|
||||||
|
fill-column: 70
|
||||||
|
coding: utf-8
|
||||||
|
End:
|
Loading…
Reference in New Issue