Maybe I’ve been drinking too much of the functional programming Kool Aid, but this behavior of list comprehensions seems like a bad design choice:
>>> d = [1, 2, 3, 4, 5]
>>> [d.pop() for _ in range(len(d))]
[5, 4, 3, 2, 1]
>>> d
[]
Why is d not copied, and then the copied lexically-scoped version not mutated (and then lost)? The point of list comprehensions seems like it should be to return the desired list, not return a list and silently mutate some other object behind the scenes. The destruction of d is somewhat implicit, which seems unPythonic. Is there a good use case for this?
Why is it advantageous to have list comps behave exactly like for loops, rather than behave more like functions (from a functional language, with local scope)?
Python never does copy unless you specifically ask it to do a copy. This is a perfectly simple, clear, and totally understandable rule. Putting exceptions and distinguos on it, such as “except under the following circumstances within a list comprehension…”, would be utter folly: if Python’s design had ever been under the management of somebody with such crazy ideas, Python would be a sick, contorted, half-broken language not worth learning. Thanks for making me happy all over again in the realization that is is definitely not the case!
You want a copy? Make a copy! That’s always the solution in Python when you prefer a copy’s overhead because you need to perform some changes that must not be reflected in the original. That is, in a clean approach, you’d do
If you’re super-keen to have everything within a single expression, you can, though it’s possibly not code one would call exactly “clean”:
i.e., the usual trick one uses when one would really like to fold an assignment into a list comprehension (add a
forclause, with the “control variable” being the name you want to assign to, and the “loop” is over a single-item sequence of the value you want to assign).Functional languages never mutate data, therefore they don’t make copies either (nor do they need to). Python is not a functional language, but of course there’s a lot of things you can do in Python “the functional way”, and often it’s a better way. For example, a much better replacement for your list comprehension (guaranteed to have identical results and not affect
d, and vastly faster, more concise, and cleaner):(AKA “the Martian Smiley”, per my wife Anna;-). Slicing (not slice assignment, which is a different operation) always perform a copy in core Python (language and standard library), though of course not necessarily in independently developed third party modules like the popular
numpy(which prefers to see a slice as a “view” on the originalnumpy.array).