List comprehension and in place methods

Question:

I am just trying to understand what happens during list comprehension. Some methods which work on lists ‘in-place’ don’t seem to work when applied in a list comprehension:

a = [[1, 2, 3], [4, 5, 6]]
i1 = id(a[0])

for i in a: i.reverse()
>>> [[3, 2, 1], [6, 5, 4]  # Works
print i1 == id(a[0])  # True, same memory address

a = [i.reverse() for i in a]
>>> [None, None]  # Doesn't work
print i1 == id(a[0])  # False, new memory address

a = [i[::-1] for i in a]
>>> [[3, 2, 1], [6, 5, 4]]  # Works!
print i1 == id(a[0])  # False

I am guessing this has something to do with all the elements getting copied to a different memory space. Why does i[::-1] work whereas i.reverse() doesn’t?

Asked By: kezzos

||

Answers:

i.reverse() reverses the array in place and doesn’t return anything, meaning it returns None type. That way you obtain [None, None] from list comprehension and previous arrays’ elements are reversed at the same time.

These two shouldn’t be mixed, either use a for and x.reverse(), or use reversed(x) or x[::-1] in a list comprehension.

Answered By: rr-

i.reverse() reverses the list in-place and returns None.

What the docs say:

list.reverse()

Reverse the elements of the list, in place

vs.

reversed(seq)

Return a reverse iterator. seq must be an object which has a
__reversed__() method or supports the sequence protocol
(the __len__() method and the __getitem__() method with integer arguments starting at 0).

Examples:

>>> xs = [1, 2, 3]
>>> id(xs)
140625121860208
>>> ys = xs[::-1]
>>> id(ys)
140625121924088

Slicing creates a new list.

>>> xs.reverse()
>>> xs
[3, 2, 1]
>>> id(xs)
140625121860208

In-place sorting/reversing retains the original list.

>>> zs = list(reversed(xs))
>>> zs
[1, 2, 3]
>>> id(zs)
140625121976400

reversed() returns an iterator; which when turns into a list creates a new list! If you have a read of PEP 0322 — Reverse Iteration you’ll note that reversed() does not create a new data structure but simply iteratoes over the sequence in reverse order.

Answered By: James Mills

This does what you intend:

>>> a = [[1, 2, 3], [4, 5, 6]]
>>> [list(reversed(i)) for i in a]
[[3, 2, 1], [6, 5, 4]]

List comprehension always returns a new list, so using the in-place reverse
method just returns the return value of reverse, which is None.

The function reversed() gives you an new iterator. Converting it to
a list is for your example the same as:

>>> [i[::-1] for i in a] 

Even though they look very similar, it is important to distinguish both,
the function reversed() and the method obj.reverse()

Answered By: Mike Müller

list.reverse reverses a list in place, and return None.
while slice a[::-1] creates another list and return as value.

list comprehension will take the return value of each expression.

Answered By: cizixs
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.