Add PEP 3114: renaming .next() to .__next__().
This commit is contained in:
parent
b515f0caf7
commit
7d90144644
|
@ -0,0 +1,210 @@
|
|||
PEP: 3114
|
||||
Title: Renaming iterator.next() to iterator.__next__()
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Ka-Ping Yee <ping@zesty.ca>
|
||||
Status: Accepted
|
||||
Type: Standards Track
|
||||
Python-version: 3.0
|
||||
Content-Type: text/x-rst
|
||||
Created: 04-Mar-2007
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
The iterator protocol in Python 2.x consists of two methods:
|
||||
``__iter__()`` called on an iterable object to yield an iterator, and
|
||||
``next()`` called on an iterator object to yield the next item in the
|
||||
sequence. Using a ``for`` loop to iterate over an iterable object
|
||||
implicitly calls both of these methods. This PEP proposes that the
|
||||
``next`` method be renamed to ``__next__``, consistent with all the
|
||||
other protocols in Python in which a method is implicitly called as
|
||||
part of a language-level protocol, and that a built-in function named
|
||||
``next`` be introduced to invoke ``__next__`` method, consistent with
|
||||
the manner in which other protocols are explicitly invoked.
|
||||
|
||||
|
||||
Names With Double Underscores
|
||||
=============================
|
||||
|
||||
In Python, double underscores before and after a name are used to
|
||||
distinguish names that belong to the language itself. Attributes and
|
||||
methods that are implicitly used or created by the interpreter employ
|
||||
this naming convention; some examples are:
|
||||
|
||||
* ``__file__`` - an attribute automatically created by the interpreter
|
||||
|
||||
* ``__dict__`` - an attribute with special meaning to the interpreter
|
||||
|
||||
* ``__init__`` - a method implicitly called by the interpreter
|
||||
|
||||
Note that this convention applies to methods such as ``__init__`` that
|
||||
are explicitly defined by the programmer, as well as attributes such as
|
||||
``__file__`` that can only be accessed by naming them explicitly, so it
|
||||
includes names that are used *or* created by the interpreter.
|
||||
|
||||
(Not all things that are called "protocols" are made of methods with
|
||||
double-underscore names. For example, the ``__contains__`` method has
|
||||
double underscores because the language construct ``x in y`` implicitly
|
||||
calls ``__contains__``. But even though the ``read`` method is part of
|
||||
the file protocol, it does not have double underscores because there is
|
||||
no language construct that implicitly invokes ``x.read()``.)
|
||||
|
||||
The use of double underscores creates a separate namespace for names
|
||||
that are part of the Python language definition, so that programmers
|
||||
are free to create variables, attributes, and methods that start with
|
||||
letters, without fear of silently colliding with names that have a
|
||||
language-defined purpose. (Colliding with reserved keywords is still
|
||||
a concern, but at least this will immediately yield a syntax error.)
|
||||
|
||||
The naming of the ``next`` method on iterators is an exception to
|
||||
this convention. Code that nowhere contains an explicit call to a
|
||||
``next`` method can nonetheless be silently affected by the presence
|
||||
of such a method. Therefore, this PEP proposes that iterators should
|
||||
have a ``__next__`` method instead of a ``next`` method (with no
|
||||
change in semantics).
|
||||
|
||||
|
||||
Double-Underscore Methods and Built-In Functions
|
||||
================================================
|
||||
|
||||
The Python language defines several protocols that are implemented or
|
||||
customized by defining methods with double-underscore names. In each
|
||||
case, the protocol is provided by an internal method implemented as a
|
||||
C function in the interpreter. For objects defined in Python, this
|
||||
C function supports customization by implicitly invoking a Python method
|
||||
with a double-underscore name (it often does a little bit of additional
|
||||
work beyond just calling the Python method.)
|
||||
|
||||
Sometimes the protocol is invoked by a syntactic construct:
|
||||
|
||||
* ``x[y]`` --> internal ``tp_getitem`` --> ``x.__getitem__(y)``
|
||||
|
||||
* ``x + y`` --> internal ``nb_add`` --> ``x.__add__(y)``
|
||||
|
||||
* ``-x`` --> internal ``nb_negative`` --> ``x.__neg__()``
|
||||
|
||||
Sometimes there is no syntactic construct, but it is still useful to be
|
||||
able to explicitly invoke the protocol. For such cases Python offers a
|
||||
built-in function of the same name but without the double underscores.
|
||||
|
||||
* ``len(x)`` --> internal ``sq_length`` --> ``x.__len__()``
|
||||
|
||||
* ``hash(x)`` --> internal ``tp_hash`` --> ``x.__hash__()``
|
||||
|
||||
* ``iter(x)`` --> internal ``tp_iter`` --> ``x.__iter__()``
|
||||
|
||||
Following this pattern, the natural way to handle ``next`` is to add a
|
||||
``next`` built-in function that behaves in exactly the same fashion.
|
||||
|
||||
* ``next(x)`` --> internal ``tp_iternext`` --> ``x.__next__()``
|
||||
|
||||
Further, it is proposed that the ``next`` built-in function accept a
|
||||
sentinel value as an optional second argument, following the style of
|
||||
the ``getattr`` and ``iter`` built-in functions. When called with two
|
||||
arguments, ``next`` catches the StopIteration exception and returns
|
||||
the sentinel value instead of propagating the exception. This creates
|
||||
a nice duality between ``iter`` and ``next``:
|
||||
|
||||
iter(function, sentinel) <--> next(iterator, sentinel)
|
||||
|
||||
|
||||
Previous Proposals
|
||||
==================
|
||||
|
||||
This proposal is not a new idea. The idea proposed here was supported
|
||||
by the BDFL on python-dev [1]_ and is even mentioned in the original
|
||||
iterator PEP, PEP 234::
|
||||
|
||||
(In retrospect, it might have been better to go for __next__()
|
||||
and have a new built-in, next(it), which calls it.__next__().
|
||||
But alas, it's too late; this has been deployed in Python 2.2
|
||||
since December 2001.)
|
||||
|
||||
|
||||
Objections
|
||||
==========
|
||||
|
||||
There have been a few objections to the addition of more built-ins.
|
||||
In particular, Martin von Loewis writes [2]_::
|
||||
|
||||
I dislike the introduction of more builtins unless they have a true
|
||||
generality (i.e. are likely to be needed in many programs). For this
|
||||
one, I think the normal usage of __next__ will be with a for loop, so
|
||||
I don't think one would often need an explicit next() invocation.
|
||||
|
||||
It is also not true that most protocols are explicitly invoked through
|
||||
builtin functions. Instead, most protocols are can be explicitly invoked
|
||||
through methods in the operator module. So following tradition, it
|
||||
should be operator.next.
|
||||
|
||||
...
|
||||
|
||||
As an alternative, I propose that object grows a .next() method,
|
||||
which calls __next__ by default.
|
||||
|
||||
|
||||
Transition Plan
|
||||
===============
|
||||
|
||||
(This section is likely to be updated.)
|
||||
|
||||
Two additional transformations will be added to the 2to3 translation
|
||||
tool [3]_:
|
||||
|
||||
* Method definitions named ``next`` will be renamed to ``__next__``.
|
||||
|
||||
* Explicit calls to the ``next`` method will be replaced with calls
|
||||
to the built-in ``next`` function. For example, ``x.next()`` will
|
||||
become ``next(x)``.
|
||||
|
||||
If the module being processed already contains a binding for the name
|
||||
``next``, the second transformation will not be done; instead, calls to
|
||||
``x.next()`` will be replaced with ``x.__next__()`` and a warning will
|
||||
be emitted. (Collin Winter has looked into this [4]_ and found that
|
||||
it's difficult to make the second transformation depend on the presence
|
||||
of a module-level binding; warning about the existence of bindings to
|
||||
``next`` should be possible, though.)
|
||||
|
||||
|
||||
Approval
|
||||
========
|
||||
|
||||
This PEP was accepted by Guido on March 6, 2007 [5]_.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Single- vs. Multi-pass iterability (Guido van Rossum)
|
||||
http://mail.python.org/pipermail/python-dev/2002-July/026814.html
|
||||
|
||||
.. [2] PEP: rename it.next() to it.__next__()... (Martin von Loewis)
|
||||
http://mail.python.org/pipermail/python-3000/2007-March/005965.html
|
||||
|
||||
.. [3] 2to3 refactoring tool
|
||||
http://svn.python.org/view/sandbox/trunk/2to3/
|
||||
|
||||
.. [4] PEP: rename it.next() to it.__next__()... (Collin Winter)
|
||||
http://mail.python.org/pipermail/python-3000/2007-March/006020.html
|
||||
|
||||
.. [5] PEP: rename it.next() to it.__next__()... (Guido van Rossum)
|
||||
http://mail.python.org/pipermail/python-3000/2007-March/006027.html
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
Loading…
Reference in New Issue