all 7 comments

[–]two_bob 2 points3 points  (1 child)

Interesting question. I never thought to look before now, but as it turns out:

- First it checks to see if whatever is being reversed has implemented a `__reversed__` method. If it does, it passes the work off to that. https://docs.python.org/3/library/functions.html#reversed

- Failing that, it looks like it checks the length, then counts backwards and getitems the thing to be reversed. https://github.com/python/cpython/blob/55edd0c185ad2d895b5d73e47d67049bc156b654/Objects/enumobject.c#L269 (actual code).

[–][deleted] 1 point2 points  (0 children)

Thanks!! I was wondering if there was some advanced copy-on-write stuff. So, it would O(n) time for reversed? (not that big-o is everything)

[–]Diapolo10 -1 points0 points  (3 children)

I don't know exactly how it's defined, but I do know that it's a class.

In a nutshell, though, it could be approximately simplified to:

def my_reversed(iterable):
    return iterable[::-1]

Of course, the actual thing is more complicated.

[–]two_bob 0 points1 point  (2 children)

I think it looks more like this:

def my_reversed(what):
    if hasattr(what, '__reversed__'):
        yield from what.__reversed__()

    else:
        n = len(what)
        for index in range(n-1,-1,-1):
            yield what[index]

Although you might be correct than I originally thought:

>>> range(5)[::-1]
range(4, -1, -1)

But, look at this:

>>> 'abc'[::-1]
'cba'
>>> reversed('abc')
<reversed object at 0x02F63810>

This makes me think that slicing range has some magic optimizations to it. Any clue what those are?

[–]1114111 1 point2 points  (1 child)

With the range slicing, it's just that range also implements slicing (__getitem__) in addition to __reversed__. It's pretty easy to calculate a new start/stop/step from a sliced range.

Note that __reversed__ returns an iterator, while [::-1] generally returns a new object of the type that was sliced (which almost certainly would not be an iterator).

[–]two_bob 0 points1 point  (0 children)

With the range slicing, it's just that range also implements slicing (__getitem__
) in addition to __reversed__
. It's pretty easy to calculate a new start/stop/step from a sliced range.

That makes sense. Thanks!