List comprehensions are a concise way to create lists based on existing iterable objects using a short syntax:
squares = [x**2 for x in range(10)]
This notation is equivalent to:
squares = [] for x in range(10): squares.append(x**2)
List comprehensions have several advantages:
evens = [x for x in range(10) if x % 2 == 0];The equivalent with map():
def f(x): return x**2 squares = list(map(f, range(10)))
map is faster on large data sets if a function already implemented in C is used, and is suitable for applying a single function to all elements. List comprehension is for any expressions, not just ready-made functions. The for loop is more flexible, but more verbose.
Why is the variable x accessible outside the expression in Python2, but not in Python3 after executing the expression
[x for x in range(10)]?
Answer: In Python2, the loop variable (x) retains its value after executing the list comprehension. In Python3, it is "isolated" and not accessible outside the list, preventing undesirable side effects.
Example:
# Python 2.x: [x for x in range(3)] print(x) # x == 2 # Python 3.x: [x for x in range(3)] print(x) # NameError: name 'x' is not defined
Story 1
A developer on a large project wanted to filter and create a new list through list comprehension:
my_list = [item.transform() for item in data if item.is_valid()]
But the operation item.transform() raised an error if item.is_valid() returned False. However, the validation function had a potential side effect, and as a result, the list comprehension inconspicuously broke parts of the code with side effects.
Story 2
During the migration from Python2 to Python3, a developer was sure the loop variable would remain accessible:
[x for x in range(5)] print(x) # Expected to get 4, but received NameError.
This caused a bug in the loop logic where the variable was supposed to remain valid outside the comprehension.
Story 3
Using nested list comprehensions without clearly indicating the levels:
def flatten(matrix): return [cell for row in matrix for cell in row]
Novices often make errors due to mistaken traversal order (for example, [cell for cell in row for row in matrix] or excessive nesting), leading to incorrect results—a one-dimensional list instead of two-dimensional or vice versa.