List comprehension appeared in early versions of Python. This syntactic sugar was borrowed from functional languages. It makes the code more compact and sometimes even a bit faster than a regular for loop.
Many inexperienced developers use list comprehensions without understanding their peculiarities, leading to decreased readability or unexpected effects in the code. Additionally, new developers often struggle to distinguish between using list comprehensions and the map/filter/lambda functions.
List comprehension is a way to quickly create a new list by applying an expression to each element of the original sequence:
nums = [1, 2, 3, 4] squares = [x*x for x in nums if x % 2 == 0] # [4, 16]
Key features:
Does list comprehension return a generator?
No, it returns a list. A generator is created using parentheses:
# This is a generator: (x*x for x in range(10)) # This is a list: [x*x for x in range(10)]
Can values be assigned to variables inside list comprehension?
In standard syntax, no. Only using the "walrus" expression (:=) from Python 3.8+:
[x for x in (y := range(5))] # Error! [x for x in [(y := i*i) for i in range(5)]] # y is only visible within this list
Can external variables be modified inside list comprehension?
A variable declared inside a list comprehension is local and will not be visible outside. This often confuses newcomers in nested constructs.
Negative case A developer uses nested list comprehensions for a complex data transformation in one line. Pros: The code is compact, there’s an effect of "I know Python!" Cons: Hard to read, new colleagues struggle, debugging becomes torturous. Positive case A developer uses simple list comprehensions for filtering and transforming short lists, and for complex operations writes explicit functions and loops. Pros: The code is easy to read, maintain, and extend. Cons: In some cases, the code is a bit longer and uses additional variables.