added PEPs 359 (The "make Statement) and 3002 (Procedure for Backwards-Incompatible Changes) by Steven Bethard

This commit is contained in:
David Goodger 2006-04-13 13:36:24 +00:00
parent 5d38f6aa3a
commit 7c39299824
3 changed files with 443 additions and 0 deletions

View File

@ -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

274
pep-0359.txt Normal file
View File

@ -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:

164
pep-3002.txt Normal file
View File

@ -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: