Title: improve documentation for enumerate() (built-in function)
Type: enhancement Stage: resolved
Components: Documentation Versions: Python 3.5, Python 3.4, Python 2.7
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Arfrever, docs@python, ethan.furman, ezio.melotti, georg.brandl, r.david.murray, rhettinger, terry.reedy, tshepang, vy0123
Priority: normal Keywords: patch

Created on 2014-10-25 03:43 by vy0123, last changed 2015-06-02 19:33 by r.david.murray. This issue is now closed.

File name Uploaded Description Edit
enumerate-doc.2.7.patch r.david.murray, 2014-11-02 18:04 review
enumerate_doc-3.4.patch r.david.murray, 2014-11-02 18:05 review
Messages (27)
msg229979 - (view) Author: Van Ly (vy0123) * Date: 2014-10-25 03:43
The existing documentation is confusing. 

— improve wording as follows

enumerate(sequence, start=0)

Returns pairings of index into sequence[link to glossary.html#term-sequence] with the object at that index in the sequence.

— wording as found in v.2.7.5

enumerate(sequence, start=0)

Return an enumerate object. sequence must be a sequence, an iterator, or some other object which supports iteration. The next() method of the iterator returned by enumerate() returns a tuple containing a count (from start which defaults to 0) and the values obtained from iterating over sequence:
msg229984 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-10-25 05:14
The existing documentation is technically correct, while your replacement leaves some things out, such as the fact that enumerate accepts an iteratable and returns an iterator that is specifically a special 'enumerate object'. (A sequence is an iteratable, but not all iterables sequences, and enumerate specifically does *not* return a list of pairs, and it is important to know that).

Can you explain what it is you find confusing about the existing documentation?  The examples should go a long way toward clarifying the text for those not familiar enough with the precisely correct terms it uses.
msg229986 - (view) Author: Van Ly (vy0123) * Date: 2014-10-25 06:11
I don't want to argue. Ask a 12-year old and their English teacher, "Does the second sentence qualify as gobbledygook even if it is technically correct and complete and not verbose?"

To be constructive and take on what has been said, an iteration on improving the wording: 

-- improve wording as follows:

enumerate(iteratable, start=0)

Accepts an iteratable[typo for iterable?] and returns an iterator, a special case 'enumerate object'. The method returns a tuple which pairs an index counter with the object at the index in iterable.

>>> led = ['red', 'green', 'blue']
led = ['red', 'green', 'blue']
>>> iter = enumerate(led)
iter = enumerate(led)
(0, 'red')
(1, 'green')
(2, 'blue')

# While enumerate does not return a list of pairs, 
# it is easy to collect the pairs and construct a list as follows
>>> list(enumerate(led))
[(0, 'red'), (1, 'green'), (2, 'blue')]
msg229988 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2014-10-25 08:20
rdm was not asking for an argument, he was asking for a more detailed explanation of what was confusing.  Your initial response lacked courtesy and respect, and is not appreciated.

The rest of your reply was much better.  Next time, please skip the non-constructive portion.
msg229989 - (view) Author: Van Ly (vy0123) * Date: 2014-10-25 08:53
Understood. I felt the problem was self evident with "sequence must be a sequence".
msg229991 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2014-10-25 09:54
> I felt the problem was self evident with "sequence must be a sequence".

The two words are not used in the same sense: the first names the argument of the function, the second is one of several possible object types you can pass for that argument.
msg229992 - (view) Author: Van Ly (vy0123) * Date: 2014-10-25 10:10
> "sequence must be a sequence"

The subtle minutiae of aficionados necessary to interpret the meaning of those two words in their distinct relation is opaque to a new comer and doesn’t serve the widest possible audience usefully to get the job done quick. The second placed sense has a range of possibility narrower than iterable as has been said, all sequences are iterables but not all iterables sequences.
msg229994 - (view) Author: Van Ly (vy0123) * Date: 2014-10-25 11:20
The first mention of iterator should link to 'glossary.html#term-iterator'.

There is a builtin iter() function. This may cause confusion in earlier suggested inline sample code.

-- Use the following inline sample code 
-- in place of 'iter = enumerate(led)'to avoid confusion with iter() builtin:

led = ['red', 'green', 'blue']
iterator = enumerate(led)
    while True:
except StopIteration:
    print 'End of iterator has been reached.'
msg230006 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-10-25 15:06
I think you misunderstand the purpose of the documentation you are suggesting modifying.  It is a *reference guide*, and as such it needs to be technically precise and *must* correctly use the "jargon" of the language.  Especially since it also functions as the reference guide for people who implement new versions of Python, and need to know what behavior of things like 'enumerate' they need to reproduce.

That said, we also prefer the reference docs to be clear and understandable to someone who is a relative beginner, as long as we don't lose precision in doing so.  Thus the glossary and the glossary links, so yes it would be a good idea to add those.

I did indeed misspell iterable.

Your sentence is still incorrect...items returned by an iterator do not necessarily have an index (that is, you can't say myiterator[3] in the general case).

So, if I understand correctly, your difficulty was the confusion between the argument name *sequence* and the technical term ``sequence`` (referring to a Python object type).  I agree that that makes things confusing.  It would be better if the argument were named *iterable*, but we can't really change it at this point for backward compatibility reasons.

Maybe if we rearrange things a bit we can make it clearer.  How about this:

Return an enumerate object which when iterated[link to glossary] yields a two-tuple for each element in *sequence*, each tuple consisting of the sequence number of the element (beginning with *start*, which defaults to 0) paired with the element itself.  *sequence* must be a sequence, an iterator, or some other object which supports iteration.

That moves the distracting precise definition of *sequence* to the end, after you've already grasped what the function does.  You will note that I've also dropped the reference to next; that is implicit in the mention of "when iterated", since it is an integral part of the iteration protocol. IMO it is a distraction to mention next in this context.  It confuses the beginner and isn't needed by the expert.
msg230012 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2014-10-25 20:03
+1 for rdm's change.
msg230057 - (view) Author: Van Ly (vy0123) * Date: 2014-10-27 02:35
Reference by the guide to next() should stay for the same reason in re.compile() a regular expression object is returned and the two methods are mentioned, match() and search(). They are useful to know in that context in as much as next() is useful to know here. IMO.
msg230062 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2014-10-27 07:52
next() is quite unlike match() and search(), as you almost never use next() on iterators directly. Rather, the iterator is iterated by constructs like a for loop or a comprehension, or another function that consumes it (list, map, ...)
msg230067 - (view) Author: Van Ly (vy0123) * Date: 2014-10-27 10:37
While next() is rarely used directly on iterators, as you say, it may help to remind the experienced reader of the mechanical characteristic in essence which a new reader on first approach uses to construct a mental model.
msg230071 - (view) Author: Ethan Furman (ethan.furman) * (Python committer) Date: 2014-10-27 13:29
I do not think 'next' is needed in this context.  Unlike 'match' and 'search', 'next' is a function that can be used with any iterator and mentioning it here is unnecessary.
msg230086 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-10-27 18:50
That would not be consistent with the rest of the docs.  Consider, for example, that the full documetation of dictionary views (, which are iterables in much the same way that the enumerate object is, does not mention next.  The glossary link to iterable will lead the reader to the discussion of next, which is a fundamental Python concept and does not need to be repeated.  In my opinion, of course, others may disagree.
msg230127 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2014-10-28 08:23
rdm: your suggestion sounds good. Note that the argument name is "iterable" in Py3.
msg230409 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-10-31 23:00
The first argument of enumerate is 'iterable' in the 2.7 docstring also.

"enumerate(iterable[, start]) -> iterator for index, value of iterable

Return an enumerate object.  iterable must be another object that supportsniteration.  The enumerate object yields pairs containing a count (from\nstart, which defaults to zero) and a value yielded by the iterable argument.  enumerate is useful for obtaining an indexed list:   (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."

We should update at least that part of the doc entry.
msg230418 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-11-01 01:04
The "sequence" parameter name is an unfortunate hold-over from olden times were many things that accepted iterables were marked as taking sequences.

This was fixed in Python 3, but it can't be changed in Py2.7 because the parameter name is exposed as a keyword argument:

    >>> list(enumerate(sequence='abc', start=2))
    [(2, 'a'), (3, 'b'), (4, 'c')]

The rest docs for Python 2.7 read just fine, "Return an enumerate object. sequence must be a sequence, an iterator, or some other object which supports iteration."   I think that is sufficient to clarify any confusion caused by the unfortunate choice of keyword argument name.
msg230423 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-11-01 01:58
We have a suggestion for a wording improvement (that does not change the sentence to which you refer) that has been accepted as better than the existing wording by a couple of committers.  This improvement is actually independent of what the variable is named.  The 2.7 docstring should also be fixed to show the actual argument name, IMO.
msg230427 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-11-01 03:28
Can you attach a proposed patch and I will make a decision.  

FWIW, I'm very happy with the current documentation at  Between the text, example, and pure python equivalent, it does a great job communicating what enumerate is supposed to do.

Proposed improvements to the docstring should match the main documentation as much as possible.
msg230575 - (view) Author: Tshepang Lekhonkhobe (tshepang) * Date: 2014-11-04 04:56

Why do you say that 'sequence' is a keyword?

>>> enumerate()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Required argument 'sequence' (pos 1) not found

That means that 'sequence' can be changed to 'iterable' without worrying about backwards compatibility.
msg230578 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-11-04 05:22
static PyObject *
> Why do you say that 'sequence' is a keyword?

It is a keyword argument to enumerate().  Here's the relevant section of code:

enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
    enumobject *en;
    PyObject *seq = NULL;
    PyObject *start = NULL;
    static char *kwlist[] = {"sequence", "start", 0};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:enumerate", kwlist,
                                     &seq, &start))
        return NULL
msg230590 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2014-11-04 08:10
Specifically, this works (in 2.7):

  >>> enumerate(sequence=myvar)

Changing sequence to iterable would break any code that was written like the above.
msg230661 - (view) Author: Tshepang Lekhonkhobe (tshepang) * Date: 2014-11-05 06:22
Oh, I see now. The documentation doesn't make it clear.

Anyways, what were the advantages of making it a keyword, instead of
just a positional argument?
msg230664 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2014-11-05 07:13
Missing keyword argument support is not the norm, it's the exception that is only due to implementation details in C code. Eventually, we'd like every C function to support keyword arguments.

Converting everything is tedious work, though, and still makes things slower (that may become less of an issue eventually with Clinic), so only select functions are converted.

Functions are good candidates for keyword argument support when they have parameters that are best passed as keywords, such as

    enumerate(x, start=5)

which makes it immediately clear what the second parameter does.
msg230666 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2014-11-05 08:29
I'm sorry but I do not like the proposed patch at all.  The wording is awkward "which when iterated" and has weird terminology "the sequence number".

The OP's concern about the *sequence* versus *iterable* parameter name has been addressed (it is part of the 2.7 API and is unchangeable).

I see no need for revising the text which already discusses "sequence or some other object that supports iterable", that has clear examples, and that has pure python equivalent code.   The existing wording has worked well for most people for the better part of a decade.
msg244688 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-06-02 19:33
Per Raymond's last message, closing this as rejected.
Date User Action Args
2015-06-02 19:33:54r.david.murraysetassignee: rhettinger -> docs@python
messages: + msg244688
stage: needs patch -> resolved
2014-11-05 08:29:23rhettingersetstatus: open -> closed
resolution: rejected
messages: + msg230666
2014-11-05 07:13:18georg.brandlsetmessages: + msg230664
2014-11-05 06:22:48tshepangsetmessages: + msg230661
2014-11-04 11:49:18Arfreversetnosy: + Arfrever
2014-11-04 08:10:37r.david.murraysetmessages: + msg230590
2014-11-04 05:22:06rhettingersetmessages: + msg230578
2014-11-04 04:56:17tshepangsetnosy: + tshepang
messages: + msg230575
2014-11-02 18:05:17r.david.murraysetfiles: + enumerate_doc-3.4.patch
2014-11-02 18:04:51r.david.murraysetfiles: + enumerate-doc.2.7.patch
keywords: + patch
2014-11-01 03:28:40rhettingersetmessages: + msg230427
2014-11-01 01:58:05r.david.murraysetstatus: closed -> open
resolution: rejected -> (no value)
messages: + msg230423

versions: + Python 3.4, Python 3.5
2014-11-01 01:04:22rhettingersetstatus: open -> closed

assignee: docs@python -> rhettinger
versions: - Python 3.4, Python 3.5
nosy: + rhettinger

messages: + msg230418
resolution: rejected
2014-10-31 23:00:11terry.reedysetversions: - Python 3.6
nosy: + terry.reedy

messages: + msg230409

stage: needs patch
2014-10-28 08:23:38georg.brandlsetmessages: + msg230127
2014-10-27 18:50:45r.david.murraysetmessages: + msg230086
2014-10-27 13:29:49ethan.furmansetmessages: + msg230071
2014-10-27 10:37:29vy0123setmessages: + msg230067
2014-10-27 07:52:24georg.brandlsetnosy: + georg.brandl
messages: + msg230062
2014-10-27 02:35:15vy0123setmessages: + msg230057
2014-10-25 20:03:28ethan.furmansetmessages: + msg230012
2014-10-25 19:41:26georg.brandlsetnosy: - georg.brandl
2014-10-25 15:06:58r.david.murraysetmessages: + msg230006
2014-10-25 11:20:00vy0123setmessages: + msg229994
2014-10-25 10:10:23vy0123setmessages: + msg229992
2014-10-25 09:54:16georg.brandlsetnosy: + georg.brandl
messages: + msg229991
2014-10-25 08:53:18vy0123setmessages: + msg229989
2014-10-25 08:20:29ethan.furmansetnosy: + ethan.furman
messages: + msg229988
2014-10-25 06:11:31vy0123setmessages: + msg229986
2014-10-25 05:14:20r.david.murraysetnosy: + r.david.murray
messages: + msg229984
2014-10-25 03:56:25ezio.melottisetnosy: + ezio.melotti

versions: + Python 3.4, Python 3.6, - Python 3.3
2014-10-25 03:43:56vy0123create