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 3000 Python 3000 GvR
|
||||
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
|
||||
|
||||
Other Informational PEPs
|
||||
|
@ -102,6 +103,7 @@ Index by Category
|
|||
S 354 Enumerations in Python Finney
|
||||
S 355 Path - Object oriented filesystem paths Lindqvist
|
||||
S 358 The "bytes" Object Schemenauer
|
||||
S 359 The "make" Statement Bethard
|
||||
S 754 IEEE 754 Floating Point Special Values Warnes
|
||||
|
||||
Finished PEPs (done, implemented in Subversion)
|
||||
|
@ -415,10 +417,12 @@ Numerical Index
|
|||
I 356 Python 2.5 Release Schedule Norwitz, et al
|
||||
SF 357 Allowing Any Object to be Used for Slicing Oliphant
|
||||
S 358 The "bytes" Object Schemenauer
|
||||
S 359 The "make" Statement Bethard
|
||||
SR 666 Reject Foolish Indentation Creighton
|
||||
S 754 IEEE 754 Floating Point Special Values Warnes
|
||||
P 3000 Python 3000 GvR
|
||||
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 3100 Python 3.0 Plans Kuchling, Cannon
|
||||
|
||||
|
@ -449,6 +453,7 @@ Owners
|
|||
Batista, Facundo facundo@taniquetil.com.ar
|
||||
Baxter, Anthony anthony@interlink.com.au
|
||||
Bellman, Thomas bellman+pep-divmod@lysator.liu.se
|
||||
Bethard, Steven steven.bethard@gmail.com
|
||||
Brandl, Georg g.brandl@gmx.net
|
||||
Cannon, Brett brett@python.org
|
||||
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