Convert 10 PEPs to reSt (#180)

This commit is contained in:
Mariatta 2017-01-19 10:00:30 -08:00 committed by Brett Cannon
parent fdc405df22
commit 87dc92a34e
10 changed files with 1198 additions and 1042 deletions

View File

@ -5,163 +5,180 @@ Last-Modified: $Date$
Author: nowonder@nowonder.de (Peter Schneider-Kamp) Author: nowonder@nowonder.de (Peter Schneider-Kamp)
Status: Deferred Status: Deferred
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: 22-Aug-2000 Created: 22-Aug-2000
Python-Version: 2.1 Python-Version: 2.1
Post-History: Post-History:
Introduction Introduction
============
This PEP describes the often proposed feature of exposing the loop This PEP describes the often proposed feature of exposing the loop
counter in for-loops. This PEP tracks the status and ownership of counter in for-loops. This PEP tracks the status and ownership of
this feature. It contains a description of the feature and this feature. It contains a description of the feature and
outlines changes necessary to support the feature. This PEP outlines changes necessary to support the feature. This PEP
summarizes discussions held in mailing list forums, and provides summarizes discussions held in mailing list forums, and provides
URLs for further information, where appropriate. The CVS revision URLs for further information, where appropriate. The CVS revision
history of this file contains the definitive historical record. history of this file contains the definitive historical record.
Motivation Motivation
==========
Standard for-loops in Python iterate over the elements of a Standard for-loops in Python iterate over the elements of a
sequence[1]. Often it is desirable to loop over the indices or sequence [1]_. Often it is desirable to loop over the indices or
both the elements and the indices instead. both the elements and the indices instead.
The common idioms used to accomplish this are unintuitive. This The common idioms used to accomplish this are unintuitive. This
PEP proposes two different ways of exposing the indices. PEP proposes two different ways of exposing the indices.
Loop counter iteration Loop counter iteration
======================
The current idiom for looping over the indices makes use of the The current idiom for looping over the indices makes use of the
built-in 'range' function: built-in ``range`` function::
for i in range(len(sequence)): for i in range(len(sequence)):
# work with index i # work with index i
Looping over both elements and indices can be achieved either by the Looping over both elements and indices can be achieved either by the
old idiom or by using the new 'zip' built-in function[2]: old idiom or by using the new ``zip`` built-in function [2]_::
for i in range(len(sequence)): for i in range(len(sequence)):
e = sequence[i] e = sequence[i]
# work with index i and element e # work with index i and element e
or or::
for i, e in zip(range(len(sequence)), sequence): for i, e in zip(range(len(sequence)), sequence):
# work with index i and element e # work with index i and element e
The Proposed Solutions The Proposed Solutions
======================
There are three solutions that have been discussed. One adds a There are three solutions that have been discussed. One adds a
non-reserved keyword, the other adds two built-in functions. non-reserved keyword, the other adds two built-in functions.
A third solution adds methods to sequence objects. A third solution adds methods to sequence objects.
Non-reserved keyword 'indexing' Non-reserved keyword ``indexing``
=================================
This solution would extend the syntax of the for-loop by adding This solution would extend the syntax of the for-loop by adding
an optional '<variable> indexing' clause which can also be used an optional ``<variable> indexing`` clause which can also be used
instead of the '<variable> in' clause.. instead of the ``<variable> in`` clause.
Looping over the indices of a sequence would thus become: Looping over the indices of a sequence would thus become::
for i indexing sequence: for i indexing sequence:
# work with index i # work with index i
Looping over both indices and elements would similarly be: Looping over both indices and elements would similarly be::
for i indexing e in sequence: for i indexing e in sequence:
# work with index i and element e # work with index i and element e
Built-in functions 'indices' and 'irange' Built-in functions ``indices`` and ``irange``
=============================================
This solution adds two built-in functions 'indices' and 'irange'. This solution adds two built-in functions ``indices`` and ``irange``.
The semantics of these can be described as follows: The semantics of these can be described as follows::
def indices(sequence): def indices(sequence):
return range(len(sequence)) return range(len(sequence))
def irange(sequence): def irange(sequence):
return zip(range(len(sequence)), sequence) return zip(range(len(sequence)), sequence)
These functions could be implemented either eagerly or lazily and These functions could be implemented either eagerly or lazily and
should be easy to extend in order to accept more than one sequence should be easy to extend in order to accept more than one sequence
argument. argument.
The use of these functions would simplify the idioms for looping The use of these functions would simplify the idioms for looping
over the indices and over both elements and indices: over the indices and over both elements and indices::
for i in indices(sequence): for i in indices(sequence):
# work with index i # work with index i
for i, e in irange(sequence): for i, e in irange(sequence):
# work with index i and element e # work with index i and element e
Methods for sequence objects Methods for sequence objects
============================
This solution proposes the addition of 'indices', 'items' This solution proposes the addition of ``indices``, ``items``
and 'values' methods to sequences, which enable looping over and ``values`` methods to sequences, which enable looping over
indices only, both indices and elements, and elements only indices only, both indices and elements, and elements only
respectively. respectively.
This would immensely simplify the idioms for looping over indices This would immensely simplify the idioms for looping over indices
and for looping over both elements and indices: and for looping over both elements and indices::
for i in sequence.indices(): for i in sequence.indices():
# work with index i # work with index i
for i, e in sequence.items(): for i, e in sequence.items():
# work with index i and element e # work with index i and element e
Additionally it would allow to do looping over the elements Additionally it would allow to do looping over the elements
of sequences and dicitionaries in a consistent way: of sequences and dictionaries in a consistent way::
for e in sequence_or_dict.values(): for e in sequence_or_dict.values():
# do something with element e # do something with element e
Implementations Implementations
===============
For all three solutions some more or less rough patches exist For all three solutions some more or less rough patches exist
as patches at SourceForge: as patches at SourceForge:
'for i indexing a in l': exposing the for-loop counter[3] - ``for i indexing a in l``: exposing the for-loop counter [3]_
add indices() and irange() to built-ins[4] - add ``indices()`` and ``irange()`` to built-ins [4]_
add items() method to listobject[5] - add ``items()`` method to listobject [5]_
All of them have been pronounced on and rejected by the BDFL. All of them have been pronounced on and rejected by the BDFL.
Note that the 'indexing' keyword is only a NAME in the Note that the ``indexing`` keyword is only a ``NAME`` in the
grammar and so does not hinder the general use of 'indexing'. grammar and so does not hinder the general use of ``indexing``.
Backward Compatibility Issues Backward Compatibility Issues
=============================
As no keywords are added and the semantics of existing code As no keywords are added and the semantics of existing code
remains unchanged, all three solutions can be implemented remains unchanged, all three solutions can be implemented
without breaking existing code. without breaking existing code.
Copyright Copyright
=========
This document has been placed in the public domain. This document has been placed in the public domain.
References References
==========
[1] http://docs.python.org/reference/compound_stmts.html#for .. [1] http://docs.python.org/reference/compound_stmts.html#for
[2] Lockstep Iteration, PEP 201
[3] http://sourceforge.net/patch/download.php?id=101138 .. [2] Lockstep Iteration, PEP 201
[4] http://sourceforge.net/patch/download.php?id=101129
[5] http://sourceforge.net/patch/download.php?id=101178 .. [3] http://sourceforge.net/patch/download.php?id=101138
.. [4] http://sourceforge.net/patch/download.php?id=101129
.. [5] http://sourceforge.net/patch/download.php?id=101178
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
End: indent-tabs-mode: nil
End:

View File

@ -5,139 +5,164 @@ Last-Modified: $Date$
Author: moshez@zadka.site.co.il (Moshe Zadka) Author: moshez@zadka.site.co.il (Moshe Zadka)
Status: Rejected Status: Rejected
Type: Informational Type: Informational
Content-Type: text/x-rst
Created: 31-Jul-2000 Created: 31-Jul-2000
Post-History: Post-History:
Superseded-By: 287 Superseded-By: 287
Notice
This PEP is rejected by the author. It has been superseded by PEP Notice
287. ======
This PEP is rejected by the author. It has been superseded by PEP
287.
Abstract Abstract
========
Named Python objects, such as modules, classes and functions, have a Named Python objects, such as modules, classes and functions, have a
string attribute called __doc__. If the first expression inside string attribute called ``__doc__``. If the first expression inside
the definition is a literal string, that string is assigned the definition is a literal string, that string is assigned
to the __doc__ attribute. to the ``__doc__`` attribute.
The ``__doc__`` attribute is called a documentation string, or docstring.
It is often used to summarize the interface of the module, class or
function. However, since there is no common format for documentation
string, tools for extracting docstrings and transforming those into
documentation in a standard format (e.g., DocBook) have not sprang
up in abundance, and those that do exist are for the most part
unmaintained and unused.
The __doc__ attribute is called a documentation string, or docstring.
It is often used to summarize the interface of the module, class or
function. However, since there is no common format for documentation
string, tools for extracting docstrings and transforming those into
documentation in a standard format (e.g., DocBook) have not sprang
up in abundance, and those that do exist are for the most part
unmaintained and unused.
Perl Documentation Perl Documentation
==================
In Perl, most modules are documented in a format called POD -- Plain
Old Documentation. This is an easy-to-type, very low level format
which integrates well with the Perl parser. Many tools exist to turn
POD documentation into other formats: info, HTML and man pages, among
others. However, in Perl, the information is not available at run-time.
In Perl, most modules are documented in a format called POD -- Plain
Old Documentation. This is an easy-to-type, very low level format
which integrates well with the Perl parser. Many tools exist to turn
POD documentation into other formats: info, HTML and man pages, among
others. However, in Perl, the information is not available at run-time.
Java Documentation Java Documentation
==================
In Java, special comments before classes and functions function to
document the code. A program to extract these, and turn them into
HTML documentation is called javadoc, and is part of the standard
Java distribution. However, the only output format that is supported
is HTML, and JavaDoc has a very intimate relationship with HTML.
In Java, special comments before classes and functions function to
document the code. A program to extract these, and turn them into
HTML documentation is called javadoc, and is part of the standard
Java distribution. However, the only output format that is supported
is HTML, and JavaDoc has a very intimate relationship with HTML.
Python Docstring Goals Python Docstring Goals
======================
Python documentation string are easy to spot during parsing, and are
also available to the runtime interpreter. This double purpose is
a bit problematic, sometimes: for example, some are reluctant to have
too long docstrings, because they do not want to take much space in
the runtime. In addition, because of the current lack of tools, people
read objects' docstrings by "print"ing them, so a tendency to make them
brief and free of markups has sprung up. This tendency hinders writing
better documentation-extraction tools, since it causes docstrings to
contain little information, which is hard to parse.
Python documentation string are easy to spot during parsing, and are
also available to the runtime interpreter. This double purpose is
a bit problematic, sometimes: for example, some are reluctant to have
too long docstrings, because they do not want to take much space in
the runtime. In addition, because of the current lack of tools, people
read objects' docstrings by "print"ing them, so a tendency to make them
brief and free of markups has sprung up. This tendency hinders writing
better documentation-extraction tools, since it causes docstrings to
contain little information, which is hard to parse.
High Level Solutions High Level Solutions
====================
To counter the objection that the strings take up place in the running
program, it is suggested that documentation extraction tools will
concatenate a maximum prefix of string literals which appear in the
beginning of a definition. The first of these will also be available
in the interactive interpreter, so it should contain a few summary
lines.
To counter the objection that the strings take up place in the running
program, it is suggested that documentation extraction tools will
concatenate a maximum prefix of string literals which appear in the
beginning of a definition. The first of these will also be available
in the interactive interpreter, so it should contain a few summary
lines.
Docstring Format Goals Docstring Format Goals
======================
These are the goals for the docstring format, as discussed ad neasum These are the goals for the docstring format, as discussed ad nauseam
in the doc-sig. in the doc-sig.
1. It must be easy to type with any standard text editor.
2. It must be readable to the casual observer.
3. It must not contain information which can be deduced from parsing
the module.
4. It must contain sufficient information so it can be converted
to any reasonable markup format.
5. It must be possible to write a module's entire documentation in
docstrings, without feeling hampered by the markup language.
1. It must be easy to type with any standard text editor.
2. It must be readable to the casual observer.
3. It must not contain information which can be deduced from parsing
the module.
4. It must contain sufficient information so it can be converted
to any reasonable markup format.
5. It must be possible to write a module's entire documentation in
docstrings, without feeling hampered by the markup language.
Docstring Contents Docstring Contents
==================
For requirement 5. above, it is needed to specify what must be For requirement 5. above, it is needed to specify what must be
in docstrings. in docstrings.
At least the following must be available: At least the following must be available:
a. A tag that means "this is a Python ``something'', guess what" a. A tag that means "this is a Python `something`, guess what"
Example: In the sentence "The POP3 class", we need to markup "POP3" Example: In the sentence "The POP3 class", we need to markup "POP3"
so. The parser will be able to guess it is a class from the contents so. The parser will be able to guess it is a class from the contents
of the poplib module, but we need to make it guess. of the ``poplib`` module, but we need to make it guess.
b. Tags that mean "this is a Python class/module/class var/instance var..." b. Tags that mean "this is a Python class/module/class var/instance var..."
Example: The usual Python idiom for singleton class A is to have _A Example: The usual Python idiom for singleton class ``A`` is to have ``_A``
as the class, and A a function which returns _A objects. It's usual as the class, and ``A`` a function which returns ``_A`` objects. It's usual
to document the class, nonetheless, as being A. This requires the to document the class, nonetheless, as being ``A``. This requires the
strength to say "The class A" and have A hyperlinked and marked-up strength to say "The class ``A``" and have ``A`` hyperlinked and marked-up
as a class. as a class.
c. An easy way to include Python source code/Python interactive sessions
d. Emphasis/bold
e. List/tables
c. An easy way to include Python source code/Python interactive sessions
d. Emphasis/bold
e. List/tables
Docstring Basic Structure Docstring Basic Structure
=========================
The documentation strings will be in StructuredTextNG
(http://www.zope.org/Members/jim/StructuredTextWiki/StructuredTextNG)
Since StructuredText is not yet strong enough to handle (a) and (b)
above, we will need to extend it. I suggest using
``[<optional description>:python identifier]``.
E.g.: ``[class:POP3]``, ``[:POP3.list]``, etc. If the description is missing,
a guess will be made from the text.
The documentation strings will be in StructuredTextNG
(http://www.zope.org/Members/jim/StructuredTextWiki/StructuredTextNG)
Since StructuredText is not yet strong enough to handle (a) and (b)
above, we will need to extend it. I suggest using
'[<optional description>:python identifier]'.
E.g.: [class:POP3], [:POP3.list], etc. If the description is missing,
a guess will be made from the text.
Unresolved Issues Unresolved Issues
=================
Is there a way to escape characters in ST? If so, how?
(example: * at the beginning of a line without being bullet symbol)
Is my suggestion above for Python symbols compatible with ST-NG? Is there a way to escape characters in ST? If so, how?
How hard would it be to extend ST-NG to support it? (example: * at the beginning of a line without being bullet symbol)
How do we describe input and output types of functions? Is my suggestion above for Python symbols compatible with ST-NG?
How hard would it be to extend ST-NG to support it?
What additional constraint do we enforce on each docstring? How do we describe input and output types of functions?
(module/class/function)?
What additional constraint do we enforce on each docstring?
(module/class/function)?
What are the guesser rules?
What are the guesser rules?
Rejected Suggestions Rejected Suggestions
====================
XML -- it's very hard to type, and too cluttered to read it XML -- it's very hard to type, and too cluttered to read it comfortably.
comfortably.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
End: indent-tabs-mode: nil
End:

View File

@ -5,187 +5,195 @@ Last-Modified: $Date$
Author: gmcm@hypernet.com (Gordon McMillan) Author: gmcm@hypernet.com (Gordon McMillan)
Status: Deferred Status: Deferred
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: 14-Aug-2000 Created: 14-Aug-2000
Python-Version: 2.1 Python-Version: 2.1
Post-History: Post-History:
Introduction Introduction
============
This PEP discusses changes required to core Python in order to This PEP discusses changes required to core Python in order to
efficiently support generators, microthreads and coroutines. It is efficiently support generators, microthreads and coroutines. It is
related to PEP 220, which describes how Python should be extended related to PEP 220, which describes how Python should be extended
to support these facilities. The focus of this PEP is strictly on to support these facilities. The focus of this PEP is strictly on
the changes required to allow these extensions to work. the changes required to allow these extensions to work.
While these PEPs are based on Christian Tismer's Stackless[1] While these PEPs are based on Christian Tismer's Stackless [1]_
implementation, they do not regard Stackless as a reference implementation, they do not regard Stackless as a reference
implementation. Stackless (with an extension module) implements implementation. Stackless (with an extension module) implements
continuations, and from continuations one can implement continuations, and from continuations one can implement
coroutines, microthreads (as has been done by Will Ware[2]) and coroutines, microthreads (as has been done by Will Ware [2]_) and
generators. But in more that a year, no one has found any other generators. But in more that a year, no one has found any other
productive use of continuations, so there seems to be no demand productive use of continuations, so there seems to be no demand
for their support. for their support.
However, Stackless support for continuations is a relatively minor However, Stackless support for continuations is a relatively minor
piece of the implementation, so one might regard it as "a" piece of the implementation, so one might regard it as "a"
reference implementation (rather than "the" reference reference implementation (rather than "the" reference
implementation). implementation).
Background Background
==========
Generators and coroutines have been implemented in a number of Generators and coroutines have been implemented in a number of
languages in a number of ways. Indeed, Tim Peters has done pure languages in a number of ways. Indeed, Tim Peters has done pure
Python implementations of generators[3] and coroutines[4] using Python implementations of generators [3]_ and coroutines [4]_ using
threads (and a thread-based coroutine implementation exists for threads (and a thread-based coroutine implementation exists for
Java). However, the horrendous overhead of a thread-based Java). However, the horrendous overhead of a thread-based
implementation severely limits the usefulness of this approach. implementation severely limits the usefulness of this approach.
Microthreads (a.k.a "green" or "user" threads) and coroutines Microthreads (a.k.a "green" or "user" threads) and coroutines
involve transfers of control that are difficult to accommodate in involve transfers of control that are difficult to accommodate in
a language implementation based on a single stack. (Generators can a language implementation based on a single stack. (Generators can
be done on a single stack, but they can also be regarded as a very be done on a single stack, but they can also be regarded as a very
simple case of coroutines.) simple case of coroutines.)
Real threads allocate a full-sized stack for each thread of Real threads allocate a full-sized stack for each thread of
control, and this is the major source of overhead. However, control, and this is the major source of overhead. However,
coroutines and microthreads can be implemented in Python in a way coroutines and microthreads can be implemented in Python in a way
that involves almost no overhead. This PEP, therefor, offers a that involves almost no overhead. This PEP, therefor, offers a
way for making Python able to realistically manage thousands of way for making Python able to realistically manage thousands of
separate "threads" of activity (vs. today's limit of perhaps dozens separate "threads" of activity (vs. today's limit of perhaps dozens
of separate threads of activity). of separate threads of activity).
Another justification for this PEP (explored in PEP 220) is that Another justification for this PEP (explored in PEP 220) is that
coroutines and generators often allow a more direct expression of coroutines and generators often allow a more direct expression of
an algorithm than is possible in today's Python. an algorithm than is possible in today's Python.
Discussion Discussion
==========
The first thing to note is that Python, while it mingles The first thing to note is that Python, while it mingles
interpreter data (normal C stack usage) with Python data (the interpreter data (normal C stack usage) with Python data (the
state of the interpreted program) on the stack, the two are state of the interpreted program) on the stack, the two are
logically separate. They just happen to use the same stack. logically separate. They just happen to use the same stack.
A real thread gets something approaching a process-sized stack A real thread gets something approaching a process-sized stack
because the implementation has no way of knowing how much stack because the implementation has no way of knowing how much stack
space the thread will require. The stack space required for an space the thread will require. The stack space required for an
individual frame is likely to be reasonable, but stack switching individual frame is likely to be reasonable, but stack switching
is an arcane and non-portable process, not supported by C. is an arcane and non-portable process, not supported by C.
Once Python stops putting Python data on the C stack, however, Once Python stops putting Python data on the C stack, however,
stack switching becomes easy. stack switching becomes easy.
The fundamental approach of the PEP is based on these two The fundamental approach of the PEP is based on these two
ideas. First, separate C's stack usage from Python's stack ideas. First, separate C's stack usage from Python's stack
usage. Secondly, associate with each frame enough stack space to usage. Secondly, associate with each frame enough stack space to
handle that frame's execution. handle that frame's execution.
In the normal usage, Stackless Python has a normal stack In the normal usage, Stackless Python has a normal stack
structure, except that it is broken into chunks. But in the structure, except that it is broken into chunks. But in the
presence of a coroutine / microthread extension, this same presence of a coroutine / microthread extension, this same
mechanism supports a stack with a tree structure. That is, an mechanism supports a stack with a tree structure. That is, an
extension can support transfers of control between frames outside extension can support transfers of control between frames outside
the normal "call / return" path. the normal "call / return" path.
Problems Problems
========
The major difficulty with this approach is C calling Python. The The major difficulty with this approach is C calling Python. The
problem is that the C stack now holds a nested execution of the problem is that the C stack now holds a nested execution of the
byte-code interpreter. In that situation, a coroutine / byte-code interpreter. In that situation, a coroutine /
microthread extension cannot be permitted to transfer control to a microthread extension cannot be permitted to transfer control to a
frame in a different invocation of the byte-code interpreter. If a frame in a different invocation of the byte-code interpreter. If a
frame were to complete and exit back to C from the wrong frame were to complete and exit back to C from the wrong
interpreter, the C stack could be trashed. interpreter, the C stack could be trashed.
The ideal solution is to create a mechanism where nested The ideal solution is to create a mechanism where nested
executions of the byte code interpreter are never needed. The easy executions of the byte code interpreter are never needed. The easy
solution is for the coroutine / microthread extension(s) to solution is for the coroutine / microthread extension(s) to
recognize the situation and refuse to allow transfers outside the recognize the situation and refuse to allow transfers outside the
current invocation. current invocation.
We can categorize code that involves C calling Python into two We can categorize code that involves C calling Python into two
camps: Python's implementation, and C extensions. And hopefully we camps: Python's implementation, and C extensions. And hopefully we
can offer a compromise: Python's internal usage (and C extension can offer a compromise: Python's internal usage (and C extension
writers who want to go to the effort) will no longer use a nested writers who want to go to the effort) will no longer use a nested
invocation of the interpreter. Extensions which do not go to the invocation of the interpreter. Extensions which do not go to the
effort will still be safe, but will not play well with coroutines effort will still be safe, but will not play well with coroutines
/ microthreads. / microthreads.
Generally, when a recursive call is transformed into a loop, a bit Generally, when a recursive call is transformed into a loop, a bit
of extra bookkeeping is required. The loop will need to keep its of extra bookkeeping is required. The loop will need to keep its
own "stack" of arguments and results since the real stack can now own "stack" of arguments and results since the real stack can now
only hold the most recent. The code will be more verbose, because only hold the most recent. The code will be more verbose, because
it's not quite as obvious when we're done. While Stackless is not it's not quite as obvious when we're done. While Stackless is not
implemented this way, it has to deal with the same issues. implemented this way, it has to deal with the same issues.
In normal Python, PyEval_EvalCode is used to build a frame and In normal Python, ``PyEval_EvalCode`` is used to build a frame and
execute it. Stackless Python introduces the concept of a execute it. Stackless Python introduces the concept of a
FrameDispatcher. Like PyEval_EvalCode, it executes one frame. But ``FrameDispatcher``. Like ``PyEval_EvalCode``, it executes one frame. But
the interpreter may signal the FrameDispatcher that a new frame the interpreter may signal the ``FrameDispatcher`` that a new frame
has been swapped in, and the new frame should be executed. When a has been swapped in, and the new frame should be executed. When a
frame completes, the FrameDispatcher follows the back pointer to frame completes, the ``FrameDispatcher`` follows the back pointer to
resume the "calling" frame. resume the "calling" frame.
So Stackless transforms recursions into a loop, but it is not the So Stackless transforms recursions into a loop, but it is not the
FrameDispatcher that manages the frames. This is done by the ``FrameDispatcher`` that manages the frames. This is done by the
interpreter (or an extension that knows what it's doing). interpreter (or an extension that knows what it's doing).
The general idea is that where C code needs to execute Python The general idea is that where C code needs to execute Python
code, it creates a frame for the Python code, setting its back code, it creates a frame for the Python code, setting its back
pointer to the current frame. Then it swaps in the frame, signals pointer to the current frame. Then it swaps in the frame, signals
the FrameDispatcher and gets out of the way. The C stack is now the ``FrameDispatcher`` and gets out of the way. The C stack is now
clean - the Python code can transfer control to any other frame clean - the Python code can transfer control to any other frame
(if an extension gives it the means to do so). (if an extension gives it the means to do so).
In the vanilla case, this magic can be hidden from the programmer In the vanilla case, this magic can be hidden from the programmer
(even, in most cases, from the Python-internals programmer). Many (even, in most cases, from the Python-internals programmer). Many
situations present another level of difficulty, however. situations present another level of difficulty, however.
The map builtin function involves two obstacles to this The map builtin function involves two obstacles to this
approach. It cannot simply construct a frame and get out of the approach. It cannot simply construct a frame and get out of the
way, not just because there's a loop involved, but each pass way, not just because there's a loop involved, but each pass
through the loop requires some "post" processing. In order to play through the loop requires some "post" processing. In order to play
well with others, Stackless constructs a frame object for map well with others, Stackless constructs a frame object for map
itself. itself.
Most recursions of the interpreter are not this complex, but
fairly frequently, some "post" operations are required. Stackless
does not fix these situations because of amount of code changes
required. Instead, Stackless prohibits transfers out of a nested
interpreter. While not ideal (and sometimes puzzling), this
limitation is hardly crippling.
Most recursions of the interpreter are not this complex, but
fairly frequently, some "post" operations are required. Stackless
does not fix these situations because of amount of code changes
required. Instead, Stackless prohibits transfers out of a nested
interpreter. While not ideal (and sometimes puzzling), this
limitation is hardly crippling.
Advantages Advantages
==========
For normal Python, the advantage to this approach is that C stack For normal Python, the advantage to this approach is that C stack
usage becomes much smaller and more predictable. Unbounded usage becomes much smaller and more predictable. Unbounded
recursion in Python code becomes a memory error, instead of a recursion in Python code becomes a memory error, instead of a
stack error (and thus, in non-Cupertino operating systems, stack error (and thus, in non-Cupertino operating systems,
something that can be recovered from). The price, of course, is something that can be recovered from). The price, of course, is
the added complexity that comes from transforming recursions of the added complexity that comes from transforming recursions of
the byte-code interpreter loop into a higher order loop (and the the byte-code interpreter loop into a higher order loop (and the
attendant bookkeeping involved). attendant bookkeeping involved).
The big advantage comes from realizing that the Python stack is The big advantage comes from realizing that the Python stack is
really a tree, and the frame dispatcher can transfer control really a tree, and the frame dispatcher can transfer control
freely between leaf nodes of the tree, thus allowing things like freely between leaf nodes of the tree, thus allowing things like
microthreads and coroutines. microthreads and coroutines.
References References
==========
[1] http://www.stackless.com .. [1] http://www.stackless.com
[2] http://world.std.com/~wware/uthread.html .. [2] http://web.archive.org/web/20000815070602/http://world.std.com/~wware/uthread.html
[3] Demo/threads/Generator.py in the source distribution .. [3] Demo/threads/Generator.py in the source distribution
[4] http://www.stackless.com/coroutines.tim.peters.html .. [4] http://www.stackless.com/coroutines.tim.peters.html
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
End: indent-tabs-mode: nil
End:

View File

@ -5,140 +5,152 @@ Last-Modified: $Date$
Author: moshez@zadka.site.co.il (Moshe Zadka), guido@python.org (Guido van Rossum) Author: moshez@zadka.site.co.il (Moshe Zadka), guido@python.org (Guido van Rossum)
Status: Withdrawn Status: Withdrawn
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: 4-Nov-2000 Created: 4-Nov-2000
Python-Version: ??
Post-History: Post-History:
Withdrawal Withdrawal
==========
This PEP has been withdrawn in favor of PEP 3141. This PEP has been withdrawn in favor of PEP 3141.
Abstract Abstract
========
Today, Python's numerical model is similar to the C numeric model: Today, Python's numerical model is similar to the C numeric model:
there are several unrelated numerical types, and when operations there are several unrelated numerical types, and when operations
between numerical types are requested, coercions happen. While between numerical types are requested, coercions happen. While
the C rationale for the numerical model is that it is very similar the C rationale for the numerical model is that it is very similar
to what happens at the hardware level, that rationale does not to what happens at the hardware level, that rationale does not
apply to Python. So, while it is acceptable to C programmers that apply to Python. So, while it is acceptable to C programmers that
2/3 == 0, it is surprising to many Python programmers. 2/3 == 0, it is surprising to many Python programmers.
NOTE: in the light of recent discussions in the newsgroup, the NOTE: in the light of recent discussions in the newsgroup, the
motivation in this PEP (and details) need to be extended. motivation in this PEP (and details) need to be extended.
Rationale Rationale
=========
In usability studies, one of the least usable aspect of Python was In usability studies, one of the least usable aspect of Python was
the fact that integer division returns the floor of the division. the fact that integer division returns the floor of the division.
This makes it hard to program correctly, requiring casts to This makes it hard to program correctly, requiring casts to
float() in various parts through the code. Python's numerical ``float()`` in various parts through the code. Python's numerical
model stems from C, while a model that might be easier to work with model stems from C, while a model that might be easier to work with
can be based on the mathematical understanding of numbers. can be based on the mathematical understanding of numbers.
Other Numerical Models Other Numerical Models
======================
Perl's numerical model is that there is one type of numbers -- Perl's numerical model is that there is one type of numbers --
floating point numbers. While it is consistent and superficially floating point numbers. While it is consistent and superficially
non-surprising, it tends to have subtle gotchas. One of these is non-surprising, it tends to have subtle gotchas. One of these is
that printing numbers is very tricky, and requires correct that printing numbers is very tricky, and requires correct
rounding. In Perl, there is also a mode where all numbers are rounding. In Perl, there is also a mode where all numbers are
integers. This mode also has its share of problems, which arise integers. This mode also has its share of problems, which arise
from the fact that there is not even an approximate way of from the fact that there is not even an approximate way of
dividing numbers and getting meaningful answers. dividing numbers and getting meaningful answers.
Suggested Interface For Python's Numerical Model Suggested Interface For Python's Numerical Model
================================================
While coercion rules will remain for add-on types and classes, the While coercion rules will remain for add-on types and classes, the
built in type system will have exactly one Python type -- a built in type system will have exactly one Python type -- a
number. There are several things which can be considered "number number. There are several things which can be considered "number
methods": methods":
1. isnatural() 1. ``isnatural()``
2. isintegral() 2. ``isintegral()``
3. isrational() 3. ``isrational()``
4. isreal() 4. ``isreal()``
5. iscomplex() 5. ``iscomplex()``
6. ``isexact()``
a. isexact() Obviously, a number which answers true to a question from 1 to 5, will
also answer true to any following question. If ``isexact()`` is not true,
then any answer might be wrong.
(But not horribly wrong: it's close to the truth.)
Obviously, a number which answers true to a question from 1 to 5, will Now, there is two thing the models promises for the field operations
also answer true to any following question. If "isexact()" is not true, (+, -, /, \*):
then any answer might be wrong.
(But not horribly wrong: it's close to the truth.)
Now, there is two thing the models promises for the field operations - If both operands satisfy ``isexact()``, the result satisfies
(+, -, /, *): ``isexact()``.
- If both operands satisfy isexact(), the result satisfies - All field rules are true, except that for not-``isexact()`` numbers,
isexact(). they might be only approximately true.
- All field rules are true, except that for not-isexact() numbers, One consequence of these two rules is that all exact calcutions
they might be only approximately true. are done as (complex) rationals: since the field laws must hold,
then::
One consequence of these two rules is that all exact calcutions (a/b)*b == a
are done as (complex) rationals: since the field laws must hold,
then
(a/b)*b == a must hold.
must hold. There is built-in function, ``inexact()`` which takes a number
and returns an inexact number which is a good approximation.
Inexact numbers must be as least as accurate as if they were
using IEEE-754.
There is built-in function, inexact() which takes a number Several of the classical Python functions will return exact numbers
and returns an inexact number which is a good approximation. even when given inexact numbers: e.g, ``int()``.
Inexact numbers must be as least as accurate as if they were
using IEEE-754.
Several of the classical Python functions will return exact numbers
even when given inexact numbers: e.g, int().
Coercion Coercion
========
The number type does not define ``nb_coerce``
Any numeric operation slot, when receiving something other then ``PyNumber``,
refuses to implement it.
The number type does not define nb_coerce
Any numeric operation slot, when receiving something other then PyNumber,
refuses to implement it.
Inexact Operations Inexact Operations
==================
The functions in the "math" module will be allowed to return The functions in the ``math`` module will be allowed to return
inexact results for exact values. However, they will never return inexact results for exact values. However, they will never return
a non-real number. The functions in the "cmath" module are also a non-real number. The functions in the ``cmath`` module are also
allowed to return an inexact result for an exact argument, and are allowed to return an inexact result for an exact argument, and are
furthermore allowed to return a complex result for a real furthermore allowed to return a complex result for a real
argument. argument.
Numerical Python Issues Numerical Python Issues
=======================
People who use Numerical Python do so for high-performance vector People who use Numerical Python do so for high-performance vector
operations. Therefore, NumPy should keep its hardware based operations. Therefore, NumPy should keep its hardware based
numeric model. numeric model.
Unresolved Issues Unresolved Issues
=================
Which number literals will be exact, and which inexact? Which number literals will be exact, and which inexact?
How do we deal with IEEE 754 operations? (probably, isnan/isinf should How do we deal with IEEE 754 operations? (probably, isnan/isinf should
be methods) be methods)
On 64-bit machines, comparisons between ints and floats may be On 64-bit machines, comparisons between ints and floats may be
broken when the comparison involves conversion to float. Ditto broken when the comparison involves conversion to float. Ditto
for comparisons between longs and floats. This can be dealt with for comparisons between longs and floats. This can be dealt with
by avoiding the conversion to float. (Due to Andrew Koenig.) by avoiding the conversion to float. (Due to Andrew Koenig.)
Copyright Copyright
=========
This document has been placed in the public domain. This document has been placed in the public domain.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
End: indent-tabs-mode: nil
End:

View File

@ -5,27 +5,30 @@ Last-Modified: $Date$
Author: Tim Peters <tim.peters@gmail.com> Author: Tim Peters <tim.peters@gmail.com>
Status: Final Status: Final
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: Created:
Python-Version: 2.1 Python-Version: 2.1
Post-History: 16 February 2001 Post-History: 16 February 2001
Note Note
====
This is essentially a retroactive PEP: the issue came up too late This is essentially a retroactive PEP: the issue came up too late
in the 2.1 release process to solicit wide opinion before deciding in the 2.1 release process to solicit wide opinion before deciding
what to do, and can't be put off until 2.2 without also delaying what to do, and can't be put off until 2.2 without also delaying
the Cygwin and MacOS X ports. the Cygwin and MacOS X ports.
Motivation Motivation
==========
File systems vary across platforms in whether or not they preserve File systems vary across platforms in whether or not they preserve
the case of filenames, and in whether or not the platform C the case of filenames, and in whether or not the platform C
library file-opening functions do or don't insist on library file-opening functions do or don't insist on
case-sensitive matches: case-sensitive matches::
case-preserving case-destroying case-preserving case-destroying
+-------------------+------------------+ +-------------------+------------------+
case-sensitive | most Unix flavors | brrrrrrrrrr | case-sensitive | most Unix flavors | brrrrrrrrrr |
+-------------------+------------------+ +-------------------+------------------+
@ -35,119 +38,122 @@ Motivation
| | OpenVMS | | | OpenVMS |
+-------------------+------------------+ +-------------------+------------------+
In the upper left box, if you create "fiLe" it's stored as "fiLe", In the upper left box, if you create "fiLe" it's stored as "fiLe",
and only open("fiLe") will open it (open("file") will not, nor and only ``open("fiLe")`` will open it ``(open("file")`` will not, nor
will the 14 other variations on that theme). will the 14 other variations on that theme).
In the lower right box, if you create "fiLe", there's no telling In the lower right box, if you create "fiLe", there's no telling
what it's stored as -- but most likely as "FILE" -- and any of the what it's stored as -- but most likely as "FILE" -- and any of the
16 obvious variations on open("FilE") will open it. 16 obvious variations on ``open("FilE")`` will open it.
The lower left box is a mix: creating "fiLe" stores "fiLe" in the The lower left box is a mix: creating "fiLe" stores "fiLe" in the
platform directory, but you don't have to match case when opening platform directory, but you don't have to match case when opening
it; any of the 16 obvious variations on open("FILe") work. it; any of the 16 obvious variations on ``open("FILe")`` work.
NONE OF THAT IS CHANGING! Python will continue to follow platform NONE OF THAT IS CHANGING! Python will continue to follow platform
conventions w.r.t. whether case is preserved when creating a file, conventions w.r.t. whether case is preserved when creating a file,
and w.r.t. whether open() requires a case-sensitive match. In and w.r.t. whether ``open()`` requires a case-sensitive match. In
practice, you should always code as if matches were practice, you should always code as if matches were
case-sensitive, else your program won't be portable. case-sensitive, else your program won't be portable.
What's proposed is to change the semantics of Python "import" What's proposed is to change the semantics of Python "import"
statements, and there *only* in the lower left box. statements, and there *only* in the lower left box.
Current Lower-Left Semantics Current Lower-Left Semantics
============================
Support for MacOSX HFS+, and for Cygwin, is new in 2.1, so nothing Support for MacOSX HFS+, and for Cygwin, is new in 2.1, so nothing
is changing there. What's changing is Windows behavior. Here are is changing there. What's changing is Windows behavior. Here are
the current rules for import on Windows: the current rules for import on Windows:
1. Despite that the filesystem is case-insensitive, Python insists 1. Despite that the filesystem is case-insensitive, Python insists
on a case-sensitive match. But not in the way the upper left on a case-sensitive match. But not in the way the upper left
box works: if you have two files, FiLe.py and file.py on box works: if you have two files, ``FiLe.py`` and ``file.py`` on
sys.path, and do ``sys.path``, and do::
import file import file
then if Python finds FiLe.py first, it raises a NameError. It then if Python finds ``FiLe.py`` first, it raises a ``NameError``. It
does *not* go on to find file.py; indeed, it's impossible to does *not* go on to find ``file.py``; indeed, it's impossible to
import any but the first case-insensitive match on sys.path, import any but the first case-insensitive match on ``sys.path``,
and then only if case matches exactly in the first and then only if case matches exactly in the first
case-insensitive match. case-insensitive match.
2. An ugly exception: if the first case-insensitive match on 2. An ugly exception: if the first case-insensitive match on
sys.path is for a file whose name is entirely in upper case ``sys.path`` is for a file whose name is entirely in upper case
(FILE.PY or FILE.PYC or FILE.PYO), then the import silently (``FILE.PY`` or ``FILE.PYC`` or ``FILE.PYO``), then the import silently
grabs that, no matter what mixture of case was used in the grabs that, no matter what mixture of case was used in the
import statement. This is apparently to cater to miserable old import statement. This is apparently to cater to miserable old
filesystems that really fit in the lower right box. But this filesystems that really fit in the lower right box. But this
exception is unique to Windows, for reasons that may or may not exception is unique to Windows, for reasons that may or may not
exist. exist.
3. And another exception: if the environment variable PYTHONCASEOK 3. And another exception: if the environment variable ``PYTHONCASEOK``
exists, Python silently grabs the first case-insensitive match exists, Python silently grabs the first case-insensitive match
of any kind. of any kind.
So these Windows rules are pretty complicated, and neither match So these Windows rules are pretty complicated, and neither match
the Unix rules nor provide semantics natural for the native the Unix rules nor provide semantics natural for the native
filesystem. That makes them hard to explain to Unix *or* Windows filesystem. That makes them hard to explain to Unix *or* Windows
users. Nevertheless, they've worked fine for years, and in users. Nevertheless, they've worked fine for years, and in
isolation there's no compelling reason to change them. isolation there's no compelling reason to change them.
However, that was before the MacOSX HFS+ and Cygwin ports arrived. However, that was before the MacOSX HFS+ and Cygwin ports arrived.
They also have case-preserving case-insensitive filesystems, but They also have case-preserving case-insensitive filesystems, but
the people doing the ports despised the Windows rules. Indeed, a the people doing the ports despised the Windows rules. Indeed, a
patch to make HFS+ act like Unix for imports got past a reviewer patch to make HFS+ act like Unix for imports got past a reviewer
and into the code base, which incidentally made Cygwin also act and into the code base, which incidentally made Cygwin also act
like Unix (but this met the unbounded approval of the Cygwin like Unix (but this met the unbounded approval of the Cygwin
folks, so they sure didn't complain -- they had patches of their folks, so they sure didn't complain -- they had patches of their
own pending to do this, but the reviewer for those balked). own pending to do this, but the reviewer for those balked).
At a higher level, we want to keep Python consistent, by following At a higher level, we want to keep Python consistent, by following
the same rules on *all* platforms with case-preserving the same rules on *all* platforms with case-preserving
case-insensitive filesystems. case-insensitive filesystems.
Proposed Semantics Proposed Semantics
==================
The proposed new semantics for the lower left box: The proposed new semantics for the lower left box:
A. If the PYTHONCASEOK environment variable exists, same as A. If the ``PYTHONCASEOK`` environment variable exists, same as
before: silently accept the first case-insensitive match of any before: silently accept the first case-insensitive match of any
kind; raise ImportError if none found. kind; raise ImportError if none found.
B. Else search sys.path for the first case-sensitive match; raise B. Else search ``sys.path`` for the first case-sensitive match; raise
ImportError if none found. ``ImportError`` if none found.
#B is the same rule as is used on Unix, so this will improve cross- #B is the same rule as is used on Unix, so this will improve cross-
platform portability. That's good. #B is also the rule the Mac platform portability. That's good. #B is also the rule the Mac
and Cygwin folks want (and wanted enough to implement themselves, and Cygwin folks want (and wanted enough to implement themselves,
multiple times, which is a powerful argument in PythonLand). It multiple times, which is a powerful argument in PythonLand). It
can't cause any existing non-exceptional Windows import to fail, can't cause any existing non-exceptional Windows import to fail,
because any existing non-exceptional Windows import finds a because any existing non-exceptional Windows import finds a
case-sensitive match first in the path -- and it still will. An case-sensitive match first in the path -- and it still will. An
exceptional Windows import currently blows up with a NameError or exceptional Windows import currently blows up with a ``NameError`` or
ImportError, in which latter case it still will, or in which ``ImportError``, in which latter case it still will, or in which
former case will continue searching, and either succeed or blow up former case will continue searching, and either succeed or blow up
with an ImportError. with an ``ImportError``.
#A is needed to cater to case-destroying filesystems mounted on Windows, #A is needed to cater to case-destroying filesystems mounted on Windows,
and *may* also be used by people so enamored of "natural" Windows and *may* also be used by people so enamored of "natural" Windows
behavior that they're willing to set an environment variable to behavior that they're willing to set an environment variable to
get it. I don't intend to implement #A for Unix too, but that's get it. I don't intend to implement #A for Unix too, but that's
just because I'm not clear on how I *could* do so efficiently (I'm just because I'm not clear on how I *could* do so efficiently (I'm
not going to slow imports under Unix just for theoretical purity). not going to slow imports under Unix just for theoretical purity).
The potential damage is here: #2 (matching on ALLCAPS.PY) is The potential damage is here: #2 (matching on ``ALLCAPS.PY``) is
proposed to be dropped. Case-destroying filesystems are a proposed to be dropped. Case-destroying filesystems are a
vanishing breed, and support for them is ugly. We're already vanishing breed, and support for them is ugly. We're already
supporting (and will continue to support) PYTHONCASEOK for their supporting (and will continue to support) ``PYTHONCASEOK`` for their
benefit, but they don't deserve multiple hacks in 2001. benefit, but they don't deserve multiple hacks in 2001.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
End: indent-tabs-mode: nil
End:

View File

@ -5,184 +5,216 @@ Last-Modified: $Date$
Author: jriehl@spaceship.com (Jonathan Riehl) Author: jriehl@spaceship.com (Jonathan Riehl)
Status: Deferred Status: Deferred
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: 24-Aug-2001 Created: 24-Aug-2001
Python-Version: 2.2 Python-Version: 2.2
Post-History: Post-History:
Abstract Abstract
========
Much like the parser module exposes the Python parser, this PEP Much like the parser module exposes the Python parser, this PEP
proposes that the parser generator used to create the Python proposes that the parser generator used to create the Python
parser, pgen, be exposed as a module in Python. parser, ``pgen``, be exposed as a module in Python.
Rationale Rationale
=========
Through the course of Pythonic history, there have been numerous Through the course of Pythonic history, there have been numerous
discussions about the creation of a Python compiler [1]. These discussions about the creation of a Python compiler [1]_. These
have resulted in several implementations of Python parsers, most have resulted in several implementations of Python parsers, most
notably the parser module currently provided in the Python notably the parser module currently provided in the Python
standard library[2] and Jeremy Hylton's compiler module[3]. standard library [2]_ and Jeremy Hylton's compiler module [3]_.
However, while multiple language changes have been proposed However, while multiple language changes have been proposed
[4][5], experimentation with the Python syntax has lacked the [4]_ [5]_, experimentation with the Python syntax has lacked the
benefit of a Python binding to the actual parser generator used to benefit of a Python binding to the actual parser generator used to
build Python. build Python.
By providing a Python wrapper analogous to Fred Drake Jr.'s parser By providing a Python wrapper analogous to Fred Drake Jr.'s parser
wrapper, but targeted at the pgen library, the following wrapper, but targeted at the ``pgen`` library, the following
assertions are made: assertions are made:
1. Reference implementations of syntax changes will be easier to 1. Reference implementations of syntax changes will be easier to
develop. Currently, a reference implementation of a syntax develop. Currently, a reference implementation of a syntax
change would require the developer to use the pgen tool from change would require the developer to use the ``pgen`` tool from
the command line. The resulting parser data structure would the command line. The resulting parser data structure would
then either have to be reworked to interface with a custom then either have to be reworked to interface with a custom
CPython implementation, or wrapped as a C extension module. CPython implementation, or wrapped as a C extension module.
2. Reference implementations of syntax changes will be easier to 2. Reference implementations of syntax changes will be easier to
distribute. Since the parser generator will be available in distribute. Since the parser generator will be available in
Python, it should follow that the resulting parser will Python, it should follow that the resulting parser will
accessible from Python. Therefore, reference implementations accessible from Python. Therefore, reference implementations
should be available as pure Python code, versus using custom should be available as pure Python code, versus using custom
versions of the existing CPython distribution, or as compilable versions of the existing CPython distribution, or as compilable
extension modules. extension modules.
3. Reference implementations of syntax changes will be easier to 3. Reference implementations of syntax changes will be easier to
discuss with a larger audience. This somewhat falls out of the discuss with a larger audience. This somewhat falls out of the
second assertion, since the community of Python users is most second assertion, since the community of Python users is most
likely larger than the community of CPython developers. likely larger than the community of CPython developers.
4. Development of small languages in Python will be further 4. Development of small languages in Python will be further
enhanced, since the additional module will be a fully enhanced, since the additional module will be a fully
functional LL(1) parser generator. functional LL(1) parser generator.
Specification Specification
=============
The proposed module will be called pgen. The pgen module will The proposed module will be called ``pgen``. The ``pgen`` module will
contain the following functions: contain the following functions:
parseGrammarFile (fileName) -> AST
The parseGrammarFile() function will read the file pointed to
by fileName and create an AST object. The AST nodes will
contain the nonterminal, numeric values of the parser
generator meta-grammar. The output AST will be an instance of
the AST extension class as provided by the parser module.
Syntax errors in the input file will cause the SyntaxError
exception to be raised.
parseGrammarString (text) -> AST ``parseGrammarFile (fileName) -> AST``
The parseGrammarString() function will follow the semantics of --------------------------------------
the parseGrammarFile(), but accept the grammar text as a
string for input, as opposed to the file name.
buildParser (grammarAst) -> DFA The ``parseGrammarFile()`` function will read the file pointed to
The buildParser() function will accept an AST object for input by fileName and create an AST object. The AST nodes will
and return a DFA (deterministic finite automaton) data contain the nonterminal, numeric values of the parser
structure. The DFA data structure will be a C extension generator meta-grammar. The output AST will be an instance of
class, much like the AST structure is provided in the parser the AST extension class as provided by the parser module.
module. If the input AST does not conform to the nonterminal Syntax errors in the input file will cause the SyntaxError
codes defined for the pgen meta-grammar, buildParser() will exception to be raised.
throw a ValueError exception.
parseFile (fileName, dfa, start) -> AST
The parseFile() function will essentially be a wrapper for the
PyParser_ParseFile() C API function. The wrapper code will
accept the DFA C extension class, and the file name. An AST
instance that conforms to the lexical values in the token
module and the nonterminal values contained in the DFA will be
output.
parseString (text, dfa, start) -> AST ``parseGrammarString (text) -> AST``
The parseString() function will operate in a similar fashion ------------------------------------
to the parseFile() function, but accept the parse text as an
argument. Much like parseFile() will wrap the
PyParser_ParseFile() C API function, parseString() will wrap
the PyParser_ParseString() function.
symbolToStringMap (dfa) -> dict The ``parseGrammarString()`` function will follow the semantics of
The symbolToStringMap() function will accept a DFA instance the ``parseGrammarFile()``, but accept the grammar text as a
and return a dictionary object that maps from the DFA's string for input, as opposed to the file name.
numeric values for its nonterminals to the string names of the
nonterminals as found in the original grammar specification
for the DFA.
stringToSymbolMap (dfa) -> dict
The stringToSymbolMap() function output a dictionary mapping
the nonterminal names of the input DFA to their corresponding
numeric values.
Extra credit will be awarded if the map generation functions and ``buildParser (grammarAst) -> DFA``
parsing functions are also methods of the DFA extension class. -----------------------------------
The ``buildParser()`` function will accept an AST object for input
and return a DFA (deterministic finite automaton) data
structure. The DFA data structure will be a C extension
class, much like the AST structure is provided in the parser
module. If the input AST does not conform to the nonterminal
codes defined for the ``pgen`` meta-grammar, ``buildParser()`` will
throw a ``ValueError`` exception.
``parseFile (fileName, dfa, start) -> AST``
-------------------------------------------
The ``parseFile()`` function will essentially be a wrapper for the
``PyParser_ParseFile()`` C API function. The wrapper code will
accept the DFA C extension class, and the file name. An AST
instance that conforms to the lexical values in the token
module and the nonterminal values contained in the DFA will be
output.
``parseString (text, dfa, start) -> AST``
-----------------------------------------
The ``parseString()`` function will operate in a similar fashion
to the ``parseFile()`` function, but accept the parse text as an
argument. Much like ``parseFile()`` will wrap the
``PyParser_ParseFile()`` C API function, ``parseString()`` will wrap
the ``PyParser_ParseString()`` function.
``symbolToStringMap (dfa) -> dict``
-----------------------------------
The ``symbolToStringMap()`` function will accept a DFA instance
and return a dictionary object that maps from the DFA's
numeric values for its nonterminals to the string names of the
nonterminals as found in the original grammar specification
for the DFA.
``stringToSymbolMap (dfa) -> dict``
-----------------------------------
The ``stringToSymbolMap()`` function output a dictionary mapping
the nonterminal names of the input DFA to their corresponding
numeric values.
Extra credit will be awarded if the map generation functions and
parsing functions are also methods of the DFA extension class.
Implementation Plan Implementation Plan
===================
A cunning plan has been devised to accomplish this enhancement: A cunning plan has been devised to accomplish this enhancement:
1. Rename the pgen functions to conform to the CPython naming 1. Rename the ``pgen`` functions to conform to the CPython naming
standards. This action may involve adding some header files to standards. This action may involve adding some header files to
the Include subdirectory. the Include subdirectory.
2. Move the pgen C modules in the Makefile.pre.in from unique pgen 2. Move the ``pgen`` C modules in the Makefile.pre.in from unique ``pgen``
elements to the Python C library. elements to the Python C library.
3. Make any needed changes to the parser module so the AST 3. Make any needed changes to the parser module so the AST
extension class understands that there are AST types it may not extension class understands that there are AST types it may not
understand. Cursory examination of the AST extension class understand. Cursory examination of the AST extension class
shows that it keeps track of whether the tree is a suite or an shows that it keeps track of whether the tree is a suite or an
expression. expression.
3. Code an additional C module in the Modules directory. The C 3. Code an additional C module in the Modules directory. The C
extension module will implement the DFA extension class and the extension module will implement the DFA extension class and the
functions outlined in the previous section. functions outlined in the previous section.
4. Add the new module to the build process. Black magic, indeed. 4. Add the new module to the build process. Black magic, indeed.
Limitations Limitations
===========
Under this proposal, would be designers of Python 3000 will still Under this proposal, would be designers of Python 3000 will still
be constrained to Python's lexical conventions. The addition, be constrained to Python's lexical conventions. The addition,
subtraction or modification of the Python lexer is outside the subtraction or modification of the Python lexer is outside the
scope of this PEP. scope of this PEP.
Reference Implementation Reference Implementation
========================
No reference implementation is currently provided. A patch No reference implementation is currently provided. A patch
was provided at some point in was provided at some point in
http://sourceforge.net/tracker/index.php?func=detail&aid=599331&group_id=5470&atid=305470 http://sourceforge.net/tracker/index.php?func=detail&aid=599331&group_id=5470&atid=305470
but that patch is no longer maintained. but that patch is no longer maintained.
References References
==========
[1] The (defunct) Python Compiler-SIG .. [1] The (defunct) Python Compiler-SIG
http://www.python.org/sigs/compiler-sig/ http://www.python.org/sigs/compiler-sig/
[2] Parser Module Documentation .. [2] Parser Module Documentation
http://docs.python.org/library/parser.html http://docs.python.org/library/parser.html
[3] Hylton, Jeremy. .. [3] Hylton, Jeremy.
http://docs.python.org/library/compiler.html http://docs.python.org/library/compiler.html
[4] Pelletier, Michel. "Python Interface Syntax", PEP-245. .. [4] Pelletier, Michel. "Python Interface Syntax", PEP-245.
http://www.python.org/dev/peps/pep-0245/ http://www.python.org/dev/peps/pep-0245/
[5] The Python Types-SIG .. [5] The Python Types-SIG
http://www.python.org/sigs/types-sig/ http://www.python.org/sigs/types-sig/
Copyright Copyright
=========
This document has been placed in the public domain. This document has been placed in the public domain.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
fill-column: 70 indent-tabs-mode: nil
End: fill-column: 70
End:

View File

@ -5,159 +5,168 @@ Last-Modified: $Date$
Author: python@rcn.com (Raymond Hettinger) Author: python@rcn.com (Raymond Hettinger)
Status: Withdrawn Status: Withdrawn
Type: Standards Track Type: Standards Track
Content-Type: text/x-rst
Created: 21-Mar-2002 Created: 21-Mar-2002
Python-Version: 2.5 Python-Version: 2.5
Post-History: Post-History:
Abstract Abstract
========
This PEP proposes to enhance generators by providing mechanisms for This PEP proposes to enhance generators by providing mechanisms for
raising exceptions and sharing data with running generators. raising exceptions and sharing data with running generators.
Status Status
======
This PEP is withdrawn. The exception raising mechanism was extended This PEP is withdrawn. The exception raising mechanism was extended
and subsumed into PEP 343. The attribute passing capability and subsumed into PEP 343. The attribute passing capability
never built a following, did not have a clear implementation, never built a following, did not have a clear implementation,
and did not have a clean way for the running generator to access and did not have a clean way for the running generator to access
its own namespace. its own namespace.
Rationale Rationale
=========
Currently, only class based iterators can provide attributes and Currently, only class based iterators can provide attributes and
exception handling. However, class based iterators are harder to exception handling. However, class based iterators are harder to
write, less compact, less readable, and slower. A better solution write, less compact, less readable, and slower. A better solution
is to enable these capabilities for generators. is to enable these capabilities for generators.
Enabling attribute assignments allows data to be passed to and from Enabling attribute assignments allows data to be passed to and from
running generators. The approach of sharing data using attributes running generators. The approach of sharing data using attributes
pervades Python. Other approaches exist but are somewhat hackish pervades Python. Other approaches exist but are somewhat hackish
in comparison. in comparison.
Another evolutionary step is to add a generator method to allow Another evolutionary step is to add a generator method to allow
exceptions to be passed to a generator. Currently, there is no exceptions to be passed to a generator. Currently, there is no
clean method for triggering exceptions from outside the generator. clean method for triggering exceptions from outside the generator.
Also, generator exception passing helps mitigate the try/finally Also, generator exception passing helps mitigate the try/finally
prohibition for generators. The need is especially acute for prohibition for generators. The need is especially acute for
generators needing to flush buffers or close resources upon termination. generators needing to flush buffers or close resources upon termination.
The two proposals are backwards compatible and require no new The two proposals are backwards compatible and require no new
keywords. They are being recommended for Python version 2.5. keywords. They are being recommended for Python version 2.5.
Specification for Generator Attributes Specification for Generator Attributes
======================================
Essentially, the proposal is to emulate attribute writing for classes. Essentially, the proposal is to emulate attribute writing for classes.
The only wrinkle is that generators lack a way to refer to instances of The only wrinkle is that generators lack a way to refer to instances of
themselves. So, the proposal is to provide a function for discovering themselves. So, the proposal is to provide a function for discovering
the reference. For example: the reference. For example::
def mygen(filename): def mygen(filename):
self = sys.get_generator() self = sys.get_generator()
myfile = open(filename) myfile = open(filename)
for line in myfile: for line in myfile:
if len(line) < 10: if len(line) < 10:
continue continue
self.pos = myfile.tell() self.pos = myfile.tell()
yield line.upper() yield line.upper()
g = mygen('sample.txt') g = mygen('sample.txt')
line1 = g.next() line1 = g.next()
print 'Position', g.pos print 'Position', g.pos
Uses for generator attributes include: Uses for generator attributes include:
1. Providing generator clients with extra information (as shown 1. Providing generator clients with extra information (as shown
above). above).
2. Externally setting control flags governing generator operation 2. Externally setting control flags governing generator operation
(possibly telling a generator when to step in or step over (possibly telling a generator when to step in or step over
data groups). data groups).
3. Writing lazy consumers with complex execution states 3. Writing lazy consumers with complex execution states
(an arithmetic encoder output stream for example). (an arithmetic encoder output stream for example).
4. Writing co-routines (as demonstrated in Dr. Mertz's articles [1]). 4. Writing co-routines (as demonstrated in Dr. Mertz's articles [1]_).
The control flow of 'yield' and 'next' is unchanged by this The control flow of 'yield' and 'next' is unchanged by this
proposal. The only change is that data can passed to and from the proposal. The only change is that data can passed to and from the
generator. Most of the underlying machinery is already in place, generator. Most of the underlying machinery is already in place,
only the access function needs to be added. only the access function needs to be added.
Specification for Generator Exception Passing: Specification for Generator Exception Passing
=============================================
Add a .throw(exception) method to the generator interface: Add a .throw(exception) method to the generator interface::
def logger(): def logger():
start = time.time() start = time.time()
log = [] log = []
try: try:
while True: while True:
log.append(time.time() - start) log.append(time.time() - start)
yield log[-1] yield log[-1]
except WriteLog: except WriteLog:
writelog(log) writelog(log)
g = logger() g = logger()
for i in [10,20,40,80,160]: for i in [10,20,40,80,160]:
testsuite(i) testsuite(i)
g.next() g.next()
g.throw(WriteLog) g.throw(WriteLog)
There is no existing work-around for triggering an exception There is no existing work-around for triggering an exception
inside a generator. It is the only case in Python where active inside a generator. It is the only case in Python where active
code cannot be excepted to or through. code cannot be excepted to or through.
Generator exception passing also helps address an intrinsic Generator exception passing also helps address an intrinsic
limitation on generators, the prohibition against their using limitation on generators, the prohibition against their using
try/finally to trigger clean-up code [2]. try/finally to trigger clean-up code [2]_.
Note A: The name of the throw method was selected for several Note A: The name of the throw method was selected for several
reasons. Raise is a keyword and so cannot be used as a method reasons. Raise is a keyword and so cannot be used as a method
name. Unlike raise which immediately raises an exception from the name. Unlike raise which immediately raises an exception from the
current execution point, throw will first return to the generator current execution point, throw will first return to the generator
and then raise the exception. The word throw is suggestive of and then raise the exception. The word throw is suggestive of
putting the exception in another location. The word throw is putting the exception in another location. The word throw is
already associated with exceptions in other languages. already associated with exceptions in other languages.
Alternative method names were considered: resolve(), signal(), Alternative method names were considered: ``resolve()``, ``signal()``,
genraise(), raiseinto(), and flush(). None of these fit as well ``genraise()``, ``raiseinto()``, and ``flush()``. None of these fit as well
as throw(). as ``throw()``.
Note B: To keep the throw() syntax simple only the instance Note B: To keep the ``throw()`` syntax simple only the instance
version of the raise syntax would be supported (no variants for version of the raise syntax would be supported (no variants for
"raise string" or "raise class, instance"). "raise string" or "raise class, instance").
Calling "g.throw(instance)" would correspond to writing Calling ``g.throw(instance)`` would correspond to writing
"raise instance" immediately after the most recent yield. ``raise instance`` immediately after the most recent yield.
References References
==========
[1] Dr. David Mertz's draft columns for Charming Python: .. [1] Dr. David Mertz's draft columns for Charming Python
http://gnosis.cx/publish/programming/charming_python_b5.txt http://gnosis.cx/publish/programming/charming_python_b5.txt
http://gnosis.cx/publish/programming/charming_python_b7.txt http://gnosis.cx/publish/programming/charming_python_b7.txt
[2] PEP 255 Simple Generators: .. [2] PEP 255 Simple Generators
http://www.python.org/dev/peps/pep-0255/ http://www.python.org/dev/peps/pep-0255/
[3] Proof-of-concept recipe: .. [3] Proof-of-concept recipe
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/164044 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/164044
Copyright Copyright
=========
This document has been placed in the public domain. This document has been placed in the public domain.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
fill-column: 70 indent-tabs-mode: nil
End: fill-column: 70
End:

View File

@ -5,181 +5,205 @@ Last-Modified: $Date$
Author: Roman Suzi <rnd@onego.ru>, Alex Martelli <aleaxit@gmail.com> Author: Roman Suzi <rnd@onego.ru>, Alex Martelli <aleaxit@gmail.com>
Status: Deferred Status: Deferred
Type: Standards Track Type: Standards Track
Content-Type: text/plain Content-Type: text/x-rst
Created: 11-Feb-2003 Created: 11-Feb-2003
Python-Version: 2.4 Python-Version: 2.4
Post-History: Post-History:
Abstract Abstract
========
This PEP proposes to make argumentless lambda keyword optional in
some cases where it is not grammatically ambiguous.
This PEP proposes to make argumentless lambda keyword optional in
some cases where it is not grammatically ambiguous.
Deferral Deferral
========
The BDFL hates the unary colon syntax. This PEP needs to go back The BDFL hates the unary colon syntax. This PEP needs to go back
to the drawing board and find a more Pythonic syntax (perhaps an to the drawing board and find a more Pythonic syntax (perhaps an
alternative unary operator). See python-dev discussion on alternative unary operator). See python-dev discussion on
17 June 2005. 17 June 2005 [1]_.
Also, it is probably a good idea to eliminate the alternative
propositions which have no chance at all. The examples section
is good and highlights the readability improvements. It would
carry more weight with additional examples and with real-world
referents (instead of the abstracted dummy calls to ``:A`` and ``:B``).
Also, it is probably a good idea to eliminate the alternative
propositions which have no chance at all. The examples section
is good and highlights the readability improvements. It would
carry more weight with additional examples and with real-world
referents (instead of the abstracted dummy calls to :A and :B).
Motivation Motivation
==========
Lambdas are useful for defining anonymous functions, e.g. for use Lambdas are useful for defining anonymous functions, e.g. for use
as callbacks or (pseudo)-lazy evaluation schemes. Often, lambdas as callbacks or (pseudo)-lazy evaluation schemes. Often, lambdas
are not used when they would be appropriate, just because the are not used when they would be appropriate, just because the
keyword "lambda" makes code look complex. Omitting lambda in some keyword "lambda" makes code look complex. Omitting lambda in some
special cases is possible, with small and backwards compatible special cases is possible, with small and backwards compatible
changes to the grammar, and provides a cheap cure against such changes to the grammar, and provides a cheap cure against such
"lambdaphobia". "lambdaphobia".
Rationale Rationale
=========
Sometimes people do not use lambdas because they fear to introduce Sometimes people do not use lambdas because they fear to introduce
a term with a theory behind it. This proposal makes introducing a term with a theory behind it. This proposal makes introducing
argumentless lambdas easier, by omitting the "lambda" keyword. argumentless lambdas easier, by omitting the "lambda" keyword.
itself. Implementation can be done simply changing grammar so it itself. Implementation can be done simply changing grammar so it
lets the "lambda" keyword be implied in a few well-known cases. lets the "lambda" keyword be implied in a few well-known cases.
In particular, adding surrounding brackets lets you specify In particular, adding surrounding brackets lets you specify
nullary lambda anywhere. nullary lambda anywhere.
Syntax Syntax
======
An argumentless "lambda" keyword can be omitted in the following An argumentless "lambda" keyword can be omitted in the following
cases: cases:
* immediately after "=" in named parameter assignment or default * immediately after "=" in named parameter assignment or default
value assignment; value assignment;
* immediately after "(" in any expression; * immediately after "(" in any expression;
* immediately after a "," in a function argument list; * immediately after a "," in a function argument list;
* immediately after a ":" in a dictionary literal; (not * immediately after a ":" in a dictionary literal; (not
implemented) implemented)
* in an assignment statement; (not implemented) * in an assignment statement; (not implemented)
Examples of Use Examples of Use
===============
1) Inline "if": 1) Inline ``if``::
def ifelse(cond, true_part, false_part): def ifelse(cond, true_part, false_part):
if cond: if cond:
return true_part() return true_part()
else: else:
return false_part() return false_part()
# old syntax: # old syntax:
print ifelse(a < b, lambda:A, lambda:B) print ifelse(a < b, lambda:A, lambda:B)
# new syntax: # new syntax:
print ifelse(a < b, :A, :B) print ifelse(a < b, :A, :B)
# parts A and B may require extensive processing, as in: # parts A and B may require extensive processing, as in:
print ifelse(a < b, :ext_proc1(A), :ext_proc2(B)) print ifelse(a < b, :ext_proc1(A), :ext_proc2(B))
2) Locking: 2) Locking::
def with(alock, acallable): def with(alock, acallable):
alock.acquire() alock.acquire()
try: try:
acallable() acallable()
finally: finally:
alock.release() alock.release()
with(mylock, :x(y(), 23, z(), 'foo')) with(mylock, :x(y(), 23, z(), 'foo'))
Implementation Implementation
==============
Implementation requires some tweaking of the Grammar/Grammar file Implementation requires some tweaking of the Grammar/Grammar file
in the Python sources, and some adjustment of in the Python sources, and some adjustment of
Modules/parsermodule.c to make syntactic and pragmatic changes. Modules/parsermodule.c to make syntactic and pragmatic changes.
(Some grammar/parser guru is needed to make a full (Some grammar/parser guru is needed to make a full
implementation.) implementation.)
Here are the changes needed to Grammar to allow implicit lambda: Here are the changes needed to Grammar to allow implicit lambda::
varargslist: (fpdef ['=' imptest] ',')* ('*' NAME [',' '**' varargslist: (fpdef ['=' imptest] ',')* ('*' NAME [',' '**'
NAME] | '**' NAME) | fpdef ['=' imptest] (',' fpdef ['=' NAME] | '**' NAME) | fpdef ['=' imptest] (',' fpdef ['='
imptest])* [','] imptest])* [',']
imptest: test | implambdef imptest: test | implambdef
atom: '(' [imptestlist] ')' | '[' [listmaker] ']' | atom: '(' [imptestlist] ')' | '[' [listmaker] ']' |
'{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+ '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
implambdef: ':' test implambdef: ':' test
imptestlist: imptest (',' imptest)* [','] imptestlist: imptest (',' imptest)* [',']
argument: [test '='] imptest argument: [test '='] imptest
Three new non-terminals are needed: imptest for the place where Three new non-terminals are needed: ``imptest`` for the place where
implicit lambda may occur, implambdef for the implicit lambda implicit lambda may occur, ``implambdef`` for the implicit lambda
definition itself, imptestlist for a place where imptest's may definition itself, ``imptestlist`` for a place where ``imptest``'s may
occur. occur.
This implementation is not complete. First, because some files in This implementation is not complete. First, because some files in
Parser module need to be updated. Second, some additional places Parser module need to be updated. Second, some additional places
aren't implemented, see Syntax section above. aren't implemented, see Syntax section above.
Discussion Discussion
==========
This feature is not a high-visibility one (the only novel part is This feature is not a high-visibility one (the only novel part is
the absence of lambda). The feature is intended to make null-ary the absence of lambda). The feature is intended to make null-ary
lambdas more appealing syntactically, to provide lazy evaluation lambdas more appealing syntactically, to provide lazy evaluation
of expressions in some simple cases. This proposal is not targeted of expressions in some simple cases. This proposal is not targeted
at more advanced cases (demanding arguments for the lambda). at more advanced cases (demanding arguments for the lambda).
There is an alternative proposition for implicit lambda: implicit There is an alternative proposition for implicit lambda: implicit
lambda with unused arguments. In this case the function defined by lambda with unused arguments. In this case the function defined by
such lambda can accept any parameters, i.e. be equivalent to: such lambda can accept any parameters, i.e. be equivalent to:
lambda *args: expr. This form would be more powerful. Grep in the ``lambda *args: expr``. This form would be more powerful. Grep in the
standard library revealed that such lambdas are indeed in use. standard library revealed that such lambdas are indeed in use.
One more extension can provide a way to have a list of parameters One more extension can provide a way to have a list of parameters
passed to a function defined by implicit lambda. However, such passed to a function defined by implicit lambda. However, such
parameters need some special name to be accessed and are unlikely parameters need some special name to be accessed and are unlikely
to be included in the language. Possible local names for such to be included in the language. Possible local names for such
parameters are: _, __args__, __. For example: parameters are: ``_``, ``__args__``, ``__``. For example::
reduce(:_[0] + _[1], [1,2,3], 0) reduce(:_[0] + _[1], [1,2,3], 0)
reduce(:__[0] + __[1], [1,2,3], 0) reduce(:__[0] + __[1], [1,2,3], 0)
reduce(:__args__[0] + __args__[1], [1,2,3], 0) reduce(:__args__[0] + __args__[1], [1,2,3], 0)
These forms do not look very nice, and in the PEP author's opinion These forms do not look very nice, and in the PEP author's opinion
do not justify the removal of the lambda keyword in such cases. do not justify the removal of the lambda keyword in such cases.
Credits Credits
=======
The idea of dropping lambda was first coined by Paul Rubin at 08
Feb 2003 16:39:30 -0800 in comp.lang.python while discussing the
thread "For review: PEP 308 - If-then-else expression" [2]_.
References
==========
.. [1] Guido van Rossum, Recommend accepting PEP 312 -- Simple Implicit Lambda
https://mail.python.org/pipermail/python-dev/2005-June/054304.html
.. [2] Guido van Rossum, For review: PEP 308 - If-then-else expression
https://mail.python.org/pipermail/python-dev/2003-February/033178.html
The idea of dropping lambda was first coined by Paul Rubin at 08
Feb 2003 16:39:30 -0800 in comp.lang.python while discussing the
thread "For review: PEP 308 - If-then-else expression".
Copyright Copyright
=========
This document has been placed in the public domain. This document has been placed in the public domain.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
sentence-end-double-space: t indent-tabs-mode: nil
fill-column: 70 sentence-end-double-space: t
End: fill-column: 70
End:

View File

@ -2,160 +2,176 @@ PEP: 315
Title: Enhanced While Loop Title: Enhanced While Loop
Version: $Revision$ Version: $Revision$
Last-Modified: $Date$ Last-Modified: $Date$
Author: Raymond Hettinger <python@rcn.com> Author: Raymond Hettinger <python@rcn.com>, W Isaac Carroll <icarroll@pobox.com>
W Isaac Carroll <icarroll@pobox.com>
Status: Rejected Status: Rejected
Type: Standards Track Type: Standards Track
Content-Type: text/plain Content-Type: text/x-rst
Created: 25-Apr-2003 Created: 25-Apr-2003
Python-Version: 2.5 Python-Version: 2.5
Post-History: Post-History:
Abstract Abstract
========
This PEP proposes adding an optional "do" clause to the beginning This PEP proposes adding an optional "do" clause to the beginning
of the while loop to make loop code clearer and reduce errors of the while loop to make loop code clearer and reduce errors
caused by code duplication. caused by code duplication.
Notice Notice
======
Rejected; see Rejected; see [1]_.
http://mail.python.org/pipermail/python-ideas/2013-June/021610.html
This PEP has been deferred since 2006; see This PEP has been deferred since 2006; see [2]_.
http://mail.python.org/pipermail/python-dev/2006-February/060718.html
Subsequent efforts to revive the PEP in April 2009 did not Subsequent efforts to revive the PEP in April 2009 did not
meet with success because no syntax emerged that could meet with success because no syntax emerged that could
compete with the following form: compete with the following form::
while True: while True:
<setup code> <setup code>
if not <condition>: if not <condition>:
break break
<loop body> <loop body>
A syntax alternative to the one proposed in the PEP was found for A syntax alternative to the one proposed in the PEP was found for
a basic do-while loop but it gained little support because the a basic do-while loop but it gained little support because the
condition was at the top: condition was at the top::
do ... while <cond>: do ... while <cond>:
<loop body> <loop body>
Users of the language are advised to use the while-True form with Users of the language are advised to use the while-True form with
an inner if-break when a do-while loop would have been appropriate. an inner if-break when a do-while loop would have been appropriate.
Motivation Motivation
==========
It is often necessary for some code to be executed before each It is often necessary for some code to be executed before each
evaluation of the while loop condition. This code is often evaluation of the while loop condition. This code is often
duplicated outside the loop, as setup code that executes once duplicated outside the loop, as setup code that executes once
before entering the loop: before entering the loop::
<setup code>
while <condition>:
<loop body>
<setup code> <setup code>
while <condition>:
<loop body>
<setup code>
The problem is that duplicated code can be a source of errors if The problem is that duplicated code can be a source of errors if
one instance is changed but the other is not. Also, the purpose one instance is changed but the other is not. Also, the purpose
of the second instance of the setup code is not clear because it of the second instance of the setup code is not clear because it
comes at the end of the loop. comes at the end of the loop.
It is possible to prevent code duplication by moving the loop It is possible to prevent code duplication by moving the loop
condition into a helper function, or an if statement in the loop condition into a helper function, or an if statement in the loop
body. However, separating the loop condition from the while body. However, separating the loop condition from the while
keyword makes the behavior of the loop less clear: keyword makes the behavior of the loop less clear::
def helper(args): def helper(args):
<setup code> <setup code>
return <condition> return <condition>
while helper(args): while helper(args):
<loop body> <loop body>
This last form has the additional drawback of requiring the loop's This last form has the additional drawback of requiring the loop's
else clause to be added to the body of the if statement, further else clause to be added to the body of the if statement, further
obscuring the loop's behavior: obscuring the loop's behavior::
while True: while True:
<setup code> <setup code>
if not <condition>: break if not <condition>: break
<loop body> <loop body>
This PEP proposes to solve these problems by adding an optional This PEP proposes to solve these problems by adding an optional
clause to the while loop, which allows the setup code to be clause to the while loop, which allows the setup code to be
expressed in a natural way: expressed in a natural way::
do: do:
<setup code> <setup code>
while <condition>: while <condition>:
<loop body> <loop body>
This keeps the loop condition with the while keyword where it This keeps the loop condition with the while keyword where it
belongs, and does not require code to be duplicated. belongs, and does not require code to be duplicated.
Syntax Syntax
======
The syntax of the while statement The syntax of the while statement::
while_stmt : "while" expression ":" suite while_stmt : "while" expression ":" suite
["else" ":" suite] ["else" ":" suite]
is extended as follows: is extended as follows::
while_stmt : ["do" ":" suite] while_stmt : ["do" ":" suite]
"while" expression ":" suite "while" expression ":" suite
["else" ":" suite] ["else" ":" suite]
Semantics of break and continue Semantics of break and continue
===============================
In the do-while loop the break statement will behave the same as In the do-while loop the break statement will behave the same as
in the standard while loop: It will immediately terminate the loop in the standard while loop: It will immediately terminate the loop
without evaluating the loop condition or executing the else without evaluating the loop condition or executing the else
clause. clause.
A continue statement in the do-while loop jumps to the while A continue statement in the do-while loop jumps to the while
condition check. condition check.
In general, when the while suite is empty (a pass statement), In general, when the while suite is empty (a pass statement),
the do-while loop and break and continue statements should match the do-while loop and break and continue statements should match
the semantics of do-while in other languages. the semantics of do-while in other languages.
Likewise, when the do suite is empty, the do-while loop and Likewise, when the do suite is empty, the do-while loop and
break and continue statements should match behavior found break and continue statements should match behavior found
in regular while loops. in regular while loops.
Future Statement Future Statement
================
Because of the new keyword "do", the statement Because of the new keyword "do", the statement::
from __future__ import do_while from __future__ import do_while
will initially be required to use the do-while form. will initially be required to use the do-while form.
Implementation Implementation
==============
The first implementation of this PEP can compile the do-while loop The first implementation of this PEP can compile the do-while loop
as an infinite loop with a test that exits the loop. as an infinite loop with a test that exits the loop.
References
==========
.. [1] Guido van Rossum, PEP 315: do-while
https://mail.python.org/pipermail/python-ideas/2013-June/021610.html
.. [2] Raymond Hettinger, release plan for 2.5 ?
https://mail.python.org/pipermail/python-dev/2006-February/060718.html
Copyright Copyright
=========
This document is placed in the public domain. This document is placed in the public domain.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
sentence-end-double-space: t indent-tabs-mode: nil
fill-column: 75 sentence-end-double-space: t
End: fill-column: 75
End:

View File

@ -5,186 +5,193 @@ Last-Modified: $Date$
Author: Talin <viridia@gmail.com> Author: Talin <viridia@gmail.com>
Status: Final Status: Final
Type: Standards Track Type: Standards Track
Content-Type: text/plain Content-Type: text/x-rst
Created: 22-Apr-2006 Created: 22-Apr-2006
Python-Version: 3.0 Python-Version: 3.0
Post-History: 28-Apr-2006, May-19-2006 Post-History: 28-Apr-2006, May-19-2006
Abstract Abstract
========
This PEP proposes a change to the way that function arguments are This PEP proposes a change to the way that function arguments are
assigned to named parameter slots. In particular, it enables the assigned to named parameter slots. In particular, it enables the
declaration of "keyword-only" arguments: arguments that can only declaration of "keyword-only" arguments: arguments that can only
be supplied by keyword and which will never be automatically be supplied by keyword and which will never be automatically
filled in by a positional argument. filled in by a positional argument.
Rationale Rationale
=========
The current Python function-calling paradigm allows arguments to The current Python function-calling paradigm allows arguments to
be specified either by position or by keyword. An argument can be be specified either by position or by keyword. An argument can be
filled in either explicitly by name, or implicitly by position. filled in either explicitly by name, or implicitly by position.
There are often cases where it is desirable for a function to take There are often cases where it is desirable for a function to take
a variable number of arguments. The Python language supports this a variable number of arguments. The Python language supports this
using the 'varargs' syntax ('*name'), which specifies that any using the 'varargs' syntax (``*name``), which specifies that any
'left over' arguments be passed into the varargs parameter as a 'left over' arguments be passed into the varargs parameter as a
tuple. tuple.
One limitation on this is that currently, all of the regular One limitation on this is that currently, all of the regular
argument slots must be filled before the vararg slot can be. argument slots must be filled before the vararg slot can be.
This is not always desirable. One can easily envision a function This is not always desirable. One can easily envision a function
which takes a variable number of arguments, but also takes one which takes a variable number of arguments, but also takes one
or more 'options' in the form of keyword arguments. Currently, or more 'options' in the form of keyword arguments. Currently,
the only way to do this is to define both a varargs argument, the only way to do this is to define both a varargs argument,
and a 'keywords' argument (**kwargs), and then manually extract and a 'keywords' argument (``**kwargs``), and then manually extract
the desired keywords from the dictionary. the desired keywords from the dictionary.
Specification Specification
=============
Syntactically, the proposed changes are fairly simple. The first Syntactically, the proposed changes are fairly simple. The first
change is to allow regular arguments to appear after a varargs change is to allow regular arguments to appear after a varargs
argument: argument::
def sortwords(*wordlist, case_sensitive=False): def sortwords(*wordlist, case_sensitive=False):
... ...
This function accepts any number of positional arguments, and it This function accepts any number of positional arguments, and it
also accepts a keyword option called 'case_sensitive'. This also accepts a keyword option called 'case_sensitive'. This
option will never be filled in by a positional argument, but option will never be filled in by a positional argument, but
must be explicitly specified by name. must be explicitly specified by name.
Keyword-only arguments are not required to have a default value. Keyword-only arguments are not required to have a default value.
Since Python requires that all arguments be bound to a value, Since Python requires that all arguments be bound to a value,
and since the only way to bind a value to a keyword-only argument and since the only way to bind a value to a keyword-only argument
is via keyword, such arguments are therefore 'required keyword' is via keyword, such arguments are therefore 'required keyword'
arguments. Such arguments must be supplied by the caller, and arguments. Such arguments must be supplied by the caller, and
they must be supplied via keyword. they must be supplied via keyword.
The second syntactical change is to allow the argument name to The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not allow for keyword-only arguments for functions that would not
otherwise take a varargs argument: otherwise take a varargs argument::
def compare(a, b, *, key=None): def compare(a, b, *, key=None):
... ...
The reasoning behind this change is as follows. Imagine for a The reasoning behind this change is as follows. Imagine for a
moment a function which takes several positional arguments, as moment a function which takes several positional arguments, as
well as a keyword argument: well as a keyword argument::
def compare(a, b, key=None): def compare(a, b, key=None):
... ...
Now, suppose you wanted to have 'key' be a keyword-only argument. Now, suppose you wanted to have 'key' be a keyword-only argument.
Under the above syntax, you could accomplish this by adding a Under the above syntax, you could accomplish this by adding a
varargs argument immediately before the keyword argument: varargs argument immediately before the keyword argument::
def compare(a, b, *ignore, key=None): def compare(a, b, *ignore, key=None):
... ...
Unfortunately, the 'ignore' argument will also suck up any Unfortunately, the 'ignore' argument will also suck up any
erroneous positional arguments that may have been supplied by the erroneous positional arguments that may have been supplied by the
caller. Given that we'd prefer any unwanted arguments to raise an caller. Given that we'd prefer any unwanted arguments to raise an
error, we could do this: error, we could do this::
def compare(a, b, *ignore, key=None): def compare(a, b, *ignore, key=None):
if ignore: # If ignore is not empty if ignore: # If ignore is not empty
raise TypeError raise TypeError
As a convenient shortcut, we can simply omit the 'ignore' name,
meaning 'don't allow any positional arguments beyond this point'.
(Note: After much discussion of alternative syntax proposals, the
BDFL has pronounced in favor of this 'single star' syntax for
indicating the end of positional parameters.)
As a convenient shortcut, we can simply omit the 'ignore' name,
meaning 'don't allow any positional arguments beyond this point'.
(Note: After much discussion of alternative syntax proposals, the
BDFL has pronounced in favor of this 'single star' syntax for
indicating the end of positional parameters.)
Function Calling Behavior Function Calling Behavior
=========================
The previous section describes the difference between the old The previous section describes the difference between the old
behavior and the new. However, it is also useful to have a behavior and the new. However, it is also useful to have a
description of the new behavior that stands by itself, without description of the new behavior that stands by itself, without
reference to the previous model. So this next section will reference to the previous model. So this next section will
attempt to provide such a description. attempt to provide such a description.
When a function is called, the input arguments are assigned to When a function is called, the input arguments are assigned to
formal parameters as follows: formal parameters as follows:
- For each formal parameter, there is a slot which will be used - For each formal parameter, there is a slot which will be used
to contain the value of the argument assigned to that to contain the value of the argument assigned to that
parameter. parameter.
- Slots which have had values assigned to them are marked as - Slots which have had values assigned to them are marked as
'filled'. Slots which have no value assigned to them yet are 'filled'. Slots which have no value assigned to them yet are
considered 'empty'. considered 'empty'.
- Initially, all slots are marked as empty. - Initially, all slots are marked as empty.
- Positional arguments are assigned first, followed by keyword - Positional arguments are assigned first, followed by keyword
arguments. arguments.
- For each positional argument: - For each positional argument:
o Attempt to bind the argument to the first unfilled * Attempt to bind the argument to the first unfilled
parameter slot. If the slot is not a vararg slot, then parameter slot. If the slot is not a vararg slot, then
mark the slot as 'filled'. mark the slot as 'filled'.
o If the next unfilled slot is a vararg slot, and it does * If the next unfilled slot is a vararg slot, and it does
not have a name, then it is an error. not have a name, then it is an error.
o Otherwise, if the next unfilled slot is a vararg slot then * Otherwise, if the next unfilled slot is a vararg slot then
all remaining non-keyword arguments are placed into the all remaining non-keyword arguments are placed into the
vararg slot. vararg slot.
- For each keyword argument: - For each keyword argument:
o If there is a parameter with the same name as the keyword, * If there is a parameter with the same name as the keyword,
then the argument value is assigned to that parameter slot. then the argument value is assigned to that parameter slot.
However, if the parameter slot is already filled, then that However, if the parameter slot is already filled, then that
is an error. is an error.
o Otherwise, if there is a 'keyword dictionary' argument, * Otherwise, if there is a 'keyword dictionary' argument,
the argument is added to the dictionary using the keyword the argument is added to the dictionary using the keyword
name as the dictionary key, unless there is already an name as the dictionary key, unless there is already an
entry with that key, in which case it is an error. entry with that key, in which case it is an error.
o Otherwise, if there is no keyword dictionary, and no * Otherwise, if there is no keyword dictionary, and no
matching named parameter, then it is an error. matching named parameter, then it is an error.
- Finally: - Finally:
o If the vararg slot is not yet filled, assign an empty tuple * If the vararg slot is not yet filled, assign an empty tuple
as its value. as its value.
o For each remaining empty slot: if there is a default value * For each remaining empty slot: if there is a default value
for that slot, then fill the slot with the default value. for that slot, then fill the slot with the default value.
If there is no default value, then it is an error. If there is no default value, then it is an error.
In accordance with the current Python implementation, any errors In accordance with the current Python implementation, any errors
encountered will be signaled by raising TypeError. (If you want encountered will be signaled by raising ``TypeError``. (If you want
something different, that's a subject for a different PEP.) something different, that's a subject for a different PEP.)
Backwards Compatibility Backwards Compatibility
=======================
The function calling behavior specified in this PEP is a superset The function calling behavior specified in this PEP is a superset
of the existing behavior - that is, it is expected that any of the existing behavior - that is, it is expected that any
existing programs will continue to work. existing programs will continue to work.
Copyright Copyright
=========
This document has been placed in the public domain. This document has been placed in the public domain.
Local Variables: ..
mode: indented-text Local Variables:
indent-tabs-mode: nil mode: indented-text
sentence-end-double-space: t indent-tabs-mode: nil
fill-column: 70 sentence-end-double-space: t
coding: utf-8 fill-column: 70
End: coding: utf-8
End: