Search code examples
pythonpython-3.xpython-itertoolspython-3.8

Why Can't I Reverse All Iterators in Python 3?


  • I can call reversed on a list.
  • I can call reversed on a range_iterator.
  • I can't call reversed on a list_iterator.
  • I can't call reversed on an itertools.accumulate.

Why can I call reversed on a list and a range_iterator, but not on a list_iterator or an itertools iterator?

>>> reversed(itertools.accumulate(reversed(x), lambda x, y: x + y))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'itertools.accumulate' object is not reversible

Solution

  • If you read the docs you'll see that reversed works on any object with the following characteristics:

    has a __reversed__() method or supports the sequence protocol (the __len__() method and the __getitem__() method with integer arguments starting at 0)

    Note, that means cannot use reversed on a range_iterator, but you can on a regular range object.

    >>> reversed(iter(range(10)))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'range_iterator' object is not reversible
    >>> reversed(range(10))
    <range_iterator object at 0x105bcac90>
    

    Also note, you can usually not reverse iterators at all, it is sequence-like iterables that are generally reversible. Or anything that supports it through the magic-method hook __reversed__(), and iterators generally have neither (usually only having support for __iter__ and __next__)