Jim - 1 year ago 65
Python Question

# python3 call to "list" has odd side-effects

Consider the following two code snippets.

Snippet 1:

``````l = range(10)
list(l)
m = reversed(l)
list(m)
l = range(-1)
list(l)
list(m)
``````

Snippet 2:

``````l = range(10)
m = reversed(l)
l = range(-1)
list(l)
list(m)
``````

The only difference between them is that Snippet 2 does not call
`list(l)`
and
`list(m)`
.

Bizzarely, the final call to
`list(m)`
in Snippet 1 returns
`[]`

whereas the final call to
`list(m)`
in Snippet 2 returns
`[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]`
.

These are different values!

This is not the behaviour I would have expected. Clearly, the earlier calls to
`list(l)`
and
`list(m)`
in Snippet 1 are triggering some kind of memory optimisation; is anybody able to explain to me precisely what is going on, please?

``````>>> l = range(10)
>>> list(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> m = reversed(l)
>>> list(m)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> l = range(-1)
>>> list(l)
[]
>>> list(m)
[]
>>>
>>> l = range(10)
>>> m = reversed(l)
>>> l = range(-1)
>>> list(l)
[]
>>> list(m)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
``````

Thank you.

`reversed` returns an iterator which is a one trick pony: it is exhausted after you feed it to `list` (which builds a list from the reversed items) the first time. In consequent runs, it will yield the empty list since `m`, the iterator supplied, is exhausted and can't yield any more values:

``````m = reversed(l)
print(m) # <range_iterator object at 0x7fc496ce6c00>
list(m)  # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
list(m)  # []
``````

In your second snippet, you haven't called `list` on `m` as you do in the first, thereby not exhausting it.

You're only calling it once, in the end, and getting the result you see

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download