Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does reverse actually reverse a Python iterator?

So I can create a reverse iterator on a list:

list(reversed([0,1,2,3]))

[3, 2, 1, 0]

I assume this simply calls getitem from index len(...)-1 to 0. But then I cannot also do this:

list(reversed(xrange(4)))

[3, 2, 1, 0]

Now I am a bit confused. Does this create the list from xrange(4) and then reverse it? If not, how does it know what the last element is and how to go backwards? I read the documentation but it didn't help.

like image 228
usual me Avatar asked Aug 05 '14 11:08

usual me


1 Answers

reversed() looks for a __reversed__ special method on the object. List objects provide this, and so does xrange():

>>> xrange(4).__reversed__()
<rangeiterator object at 0x106e2fa50>

The iterator object simply produces the values in reverse, no list object is produced.

For objects that do not implement __reversed__, the reversed() function uses the length and the __getitem__ method; e.g. reversed() is essentially equivalent to:

def reversed(seq):
    try:
        return seq.__reversed__()
    except AttributeError:
        return (seq[i] for i in xrange(len(seq) - 1, -1 , -1))

where the second part is a generator expression, evaluating lazily. The generator then accesses each item in turn starting at index (length - 1) all the way down to index 0.

like image 140
Martijn Pieters Avatar answered Sep 21 '22 10:09

Martijn Pieters