Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `mylist[:] = reversed(mylist)` work?

The following reverses a list "in-place" and works in Python 2 and 3:

>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[:] = reversed(mylist)
>>> mylist
[5, 4, 3, 2, 1]

Why/how? Since reversed gives me an iterator and doesn't copy the list beforehand, and since [:]= replaces "in-place", I am surprised. And the following, also using reversed, breaks as expected:

>>> mylist = [1, 2, 3, 4, 5]
>>> for i, item in enumerate(reversed(mylist)):
        mylist[i] = item
>>> mylist
[5, 4, 3, 4, 5]

Why doesn't the [:] = fail like that?

And yes, I do know mylist.reverse().

like image 630
Stefan Pochmann Avatar asked Jun 02 '15 18:06

Stefan Pochmann


1 Answers

CPython list slice assigment will convert the iterable to a list first by calling PySequence_Fast. Source: https://hg.python.org/cpython/file/7556df35b913/Objects/listobject.c#l611

 v_as_SF = PySequence_Fast(v, "can only assign an iterable");

Even PyPy does something similar:

def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable):
    length = w_list.length()
    start, stop = normalize_simple_slice(space, length, w_start, w_stop)
    sequence_w = space.listview(w_iterable)
    w_other = W_ListObject(space, sequence_w)
    w_list.setslice(start, 1, stop-start, w_other)

Here space.listview will call ObjSpace.unpackiterable to unpack the iterable which in turn returns a list.

like image 192
Ashwini Chaudhary Avatar answered Nov 20 '22 12:11

Ashwini Chaudhary