🎓 Velnov

🐍 Python · Topic 9 of 20

Comprehensions — Python Questions with Answers

Start with the study notes on Comprehensions (definitions, examples and a quick revision), then work through 30 practice questions, each with the correct answer and a clear explanation of why it is right. When you are ready, take this topic as an interactive quiz to test yourself.

6 easy · 15 medium · 9 hard · Part of Python: Master Python from basics to advanced - 20 topics.

Topic overview

Comprehensions – building collections in one line

1. List comprehensions

A list comprehension builds a new list from an iterable in one line: [expression for item in iterable]. It replaces the “empty list, loop, append” pattern.

squares = []
for x in range(5):
    squares.append(x ** 2)
print(squares)

print([x ** 2 for x in range(5)])   # same result
Output[0, 1, 4, 9, 16]
[0, 1, 4, 9, 16]

Example: [w.upper() for w in words], [len(w) for w in words] and [int(s) for s in strings] transform every item.

2. Filtering with if

An if at the end keeps only the items that pass the test.

print([x for x in range(10) if x % 3 == 0])
print([c for c in "hello" if c in "aeiou"])
marks = {"Ana": 92, "Ben": 45}
print([name for name, m in marks.items() if m >= 50])
Output[0, 3, 6, 9]
['e', 'o']
['Ana']

3. if-else goes at the front

To change every item (not drop any), put a conditional expression before the for.

nums = [3, -1, 5]
print([x if x > 0 else 0 for x in nums])   # transform: keeps all
print([x for x in nums if x > 0])           # filter: drops some
Output[3, 0, 5]
[3, 5]

4. Dictionary and set comprehensions

print({x: x ** 2 for x in range(1, 4)})
d = {"a": 1, "b": 2}
print({v: k for k, v in d.items()})   # swap keys and values
print(sorted({c for c in "banana"}))
Output{1: 1, 2: 4, 3: 9}
{1: 'a', 2: 'b'}
['a', 'b', 'n']

5. Nested comprehensions

Several for clauses work like nested loops, read left to right: the first for is the outer loop.

print([x + y for x in "ab" for y in "cd"])
matrix = [[1, 2], [3, 4]]
print([x for row in matrix for x in row])   # flatten
Output['ac', 'ad', 'bc', 'bd']
[1, 2, 3, 4]

6. Generator expressions

With round brackets, you get a generator expression. It produces values one at a time, instead of building a whole list, which saves memory.

gen = (x ** 2 for x in range(4))
print(list(gen))
print(sum(x * x for x in range(1_000_000)))   # no big list in memory
Output[0, 1, 4, 9]
333332833333500000

Remember: There is no “tuple comprehension”: round brackets make a generator. Use tuple(...) if you need a tuple.

7. any() and all()

nums = [3, 15, 7]
print(any(x > 10 for x in nums))
print(all(x > 0 for x in nums))
OutputTrue
True

8. The 2D grid trap

[[0] * 3] * 3 repeats the same row three times, so changing one row changes them all. A comprehension makes a fresh row each time.

bad = [[0] * 3] * 3
bad[0][0] = 9
print(bad)
good = [[0] * 3 for _ in range(3)]
good[0][0] = 9
print(good)
Output[[9, 0, 0], [9, 0, 0], [9, 0, 0]]
[[9, 0, 0], [0, 0, 0], [0, 0, 0]]

9. When to use them

Use comprehensions for simple “transform” or “filter” jobs. If the logic needs several steps or print calls, a normal loop is clearer.

Remember: In Python 3, a comprehension's loop variable does not leak outside it.

10. Common misconceptions

MisconceptionCorrect understanding
The filter if and the if-else go in the same place.A filter if goes after the for; an if-else expression goes before it.
(x for x in nums) makes a tuple.It makes a generator; use tuple(...) for a tuple.
[[0] * 3] * 3 makes three separate rows.It repeats one row three times; use a comprehension.
Comprehensions are always better than loops.Use loops when the logic is long or has side effects.
The comprehension variable stays defined afterwards.In Python 3 it has its own scope and disappears.

11. Quick revision

List comprehension
[expr for x in items].
Filter
[x for x in items if test].
Transform with if-else
[a if test else b for x in items].
Dict comprehension
{k: v for ...}.
Set comprehension
{x for ...}; duplicates removed.
Generator expression
(expr for x in items); lazy.
any()
True if at least one item passes.
all()
True if every item passes.

12. Test your understanding

  1. What does [x * 2 for x in range(3)] give?

    Show answer

    [0, 2, 4]

  2. Write a comprehension that keeps only even numbers from nums.

    Show answer

    [x for x in nums if x % 2 == 0]

  3. Where does if-else go in a comprehension?

    Show answer

    Before the for: [a if test else b for x in items].

  4. How do you build {1: 1, 2: 4, 3: 9}?

    Show answer

    {x: x ** 2 for x in range(1, 4)}

  5. How do you flatten [[1, 2], [3, 4]]?

    Show answer

    [x for row in matrix for x in row]

  6. Why use sum(x * x for x in big) instead of a list?

    Show answer

    The generator never builds the whole list in memory.

  7. What does any(x > 10 for x in [3, 15]) give?

    Show answer

    True

  8. Why is [[0] * 3] * 3 dangerous?

    Show answer

    All three rows are the same list.

Key takeaway: Comprehensions turn “make a list, loop, append” into one readable line; use round brackets for a memory-friendly generator.

Notes written by Velnov. Every code example with an output was run in Python 3 to check that the output shown is exactly what Python prints.

Key concepts in this topic

List comprehensionsrange()append()PatternsFilteringModuloFilter + transformString methodsTransformationlen()MappingTernary expressionDict comprehensionsSet comprehensionsUniquenessGeneratorsLazy evaluationMemory efficiencyjoin()Nested comprehensionsCartesian productFlatteningNested loopsTuples

Jump to: Easy · Medium · Hard

Easy questions (6)

Q1. easy

What is the output of: print([x * 2 for x in range(3)])

print([x * 2 for x in range(3)])   # [0, 2, 4]
  1. A [0, 2, 4]
  2. B [2, 4, 6]
  3. C [0, 1, 2]
  4. D [0, 2, 4, 6]

Answer: A — [0, 2, 4]

A list comprehension applies the expression (x * 2) to every value of x in range(3) = 0, 1, 2 -> [0, 2, 4].

List comprehensionsrange()

Q2. easy

Which ordinary loop is equivalent to: squares = [x**2 for x in nums]

# comprehension:
squares = [x**2 for x in nums]

# equivalent loop:
squares = []
for x in nums:
    squares.append(x**2)
  1. A squares = []\nfor x in nums:\n squares.append(x**2)
  2. B for x in nums: squares = x**2
  3. C squares = for x in nums: x**2
  4. D while nums: squares.append(x**2)

Answer: A — squares = []\nfor x in nums:\n squares.append(x**2)

A comprehension is exactly a build-a-list loop compressed to one line: create empty list, loop, append the expression. Same result, less code.

append()Patterns

Q5. easy

What is the output of: print([w.upper() for w in ["hi", "bye"]])

words = ["hi", "bye"]
print([w.upper() for w in words])   # ['HI', 'BYE']
  1. A ['HI', 'BYE']
  2. B ['hi', 'bye']
  3. C 'HI BYE'
  4. D Error

Answer: A — ['HI', 'BYE']

The expression can call any method: each word is uppercased -> ['HI', 'BYE']. Comprehensions shine for transforming every item.

String methodsTransformation

Q17. easy

What is the main reason to use a comprehension instead of a loop?

  1. A It's the only way to build lists
  2. B Shorter, clearer 'build a list from a list' code (and often slightly faster)
  3. C It uses no memory at all
  4. D Loops are deprecated

Answer: B — Shorter, clearer 'build a list from a list' code (and often slightly faster)

For simple transform/filter operations, one readable line beats four. But if the logic needs multiple steps or side effects, a normal loop is clearer - don't force everything into a comprehension.

Pythonic styleReadability

Q26. easy

What is the output of: print([len(x) for x in ["a", "bb", "ccc"]])

  1. A [1, 2, 3]
  2. B [3, 2, 1]
  3. C 6
  4. D ['a', 'bb', 'ccc']

Answer: A — [1, 2, 3]

len() of each string: 1, 2, 3. A straightforward mapping comprehension.

len()Mapping

Q28. easy

What is the output of: print([x for x in "abc"])

  1. A ['abc']
  2. B ['a', 'b', 'c']
  3. C 'abc'
  4. D Error

Answer: B — ['a', 'b', 'c']

Iterating a string yields characters, and the comprehension collects them: ['a', 'b', 'c'] - same result as list("abc").

Strings as iterableslist()

Medium questions (15)

Q3. medium

What is the output of: print([x for x in range(10) if x % 3 == 0])

print([x for x in range(10) if x % 3 == 0])
# [0, 3, 6, 9]
  1. A [3, 6, 9]
  2. B [0, 3, 6, 9]
  3. C [1, 2, 4, 5, 7, 8]
  4. D [0, 3, 6]

Answer: B — [0, 3, 6, 9]

The if clause FILTERS: only x values divisible by 3 are kept - 0, 3, 6, 9. Don't forget 0 is divisible by 3!

FilteringModulo

Q6. medium

What does this build? lengths = [len(w) for w in ["apple", "fig", "banana"]]

  1. A [5, 3, 6]
  2. B ['apple', 'fig', 'banana']
  3. C 14
  4. D [6, 3, 5]

Answer: A — [5, 3, 6]

len() runs on each word: 'apple' -> 5, 'fig' -> 3, 'banana' -> 6, giving [5, 3, 6] in the same order.

len()Mapping

Q8. medium

Which comprehension creates a DICT of squares: {1: 1, 2: 4, 3: 9}?

squares = {x: x**2 for x in range(1, 4)}
print(squares)   # {1: 1, 2: 4, 3: 9}
  1. A {x: x**2 for x in range(1, 4)}
  2. B [x: x**2 for x in range(1, 4)]
  3. C {x, x**2 for x in range(1, 4)}
  4. D dict(x**2 for x in range(1, 4))

Answer: A — {x: x**2 for x in range(1, 4)}

Dict comprehensions use braces with a key: value expression. {x: x**2 ...} maps each number to its square.

Dict comprehensions

Q9. medium

What does this produce? {c for c in "banana"}

print({c for c in "banana"})   # {'b', 'a', 'n'}
  1. A A set: {'b', 'a', 'n'} - unique characters only
  2. B A list of 6 characters
  3. C A dict
  4. D The string 'ban'

Answer: A — A set: {'b', 'a', 'n'} - unique characters only

Braces without a colon make a SET comprehension - duplicates are dropped automatically, leaving the unique characters of 'banana'.

Set comprehensionsUniqueness

Q10. medium

What is (x**2 for x in range(3)) - with PARENTHESES?

gen = (x**2 for x in range(3))
print(gen)         # <generator object ...>
print(list(gen))   # [0, 1, 4]
  1. A A tuple comprehension
  2. B A generator expression - values are produced lazily, one at a time
  3. C A syntax error
  4. D The same as a list comprehension

Answer: B — A generator expression - values are produced lazily, one at a time

Parentheses make a GENERATOR expression: nothing is computed until you iterate it, and values are produced one by one - using almost no memory. There is no 'tuple comprehension'; use tuple(...) to get a tuple.

GeneratorsLazy evaluation

Q12. medium

What is the output of: print([c for c in "hello" if c in "aeiou"])

vowels = [c for c in "hello" if c in "aeiou"]
print(vowels)             # ['e', 'o']
print("".join(vowels))   # eo
  1. A ['e', 'o']
  2. B ['h', 'l', 'l']
  3. C 'eo'
  4. D ['a', 'e', 'i', 'o', 'u']

Answer: A — ['e', 'o']

Loop over each character, keep only vowels: 'e' and 'o' -> ['e', 'o']. Use "".join(...) if you want them as one string.

Filteringjoin()

Q15. medium

Which builds a list of (number, square) PAIRS: [(1, 1), (2, 4), (3, 9)]?

pairs = [(x, x**2) for x in range(1, 4)]
print(pairs)   # [(1, 1), (2, 4), (3, 9)]
  1. A [(x, x**2) for x in range(1, 4)]
  2. B [x, x**2 for x in range(1, 4)]
  3. C {x: x**2 for x in range(1, 4)}
  4. D [(x)(x**2) for x in range(1, 4)]

Answer: A — [(x, x**2) for x in range(1, 4)]

Wrap the pair in parentheses to make a tuple per item: (x, x**2). Without the inner parentheses (option B) it's a SyntaxError.

TuplesPairs

Q16. medium

How do you swap keys and values of d = {"a": 1, "b": 2} with a comprehension?

d = {"a": 1, "b": 2}
flipped = {v: k for k, v in d.items()}
print(flipped)   # {1: 'a', 2: 'b'}
  1. A {v: k for k, v in d.items()}
  2. B {k: v for v, k in d.items()}
  3. C d.swap()
  4. D {d[k]: k for k in d.values()}

Answer: A — {v: k for k, v in d.items()}

Loop over items() to get (key, value) pairs, then write them flipped: value becomes the key -> {1: 'a', 2: 'b'}.

  • Only safe when values are unique and hashable.

Dict comprehensionsitems()

Q18. medium

What does any() return here? any(x > 10 for x in [3, 15, 7])

nums = [3, 15, 7]
print(any(x > 10 for x in nums))   # True
print(all(x > 10 for x in nums))   # False
  1. A True - at least one value passes the test
  2. B False
  3. C [False, True, False]
  4. D 15

Answer: A — True - at least one value passes the test

any() is True if AT LEAST ONE element of the iterable is truthy - 15 > 10 passes, so True. It even stops early at the first success.

any()all()Generators

Q19. medium

What does all() return here? all(x > 0 for x in [1, 2, 3])

print(all(x > 0 for x in [1, 2, 3]))    # True
print(all(x > 0 for x in [1, -2, 3]))   # False
  1. A False
  2. B True - every element passes
  3. C 3
  4. D [True, True, True]

Answer: B — True - every element passes

all() is True only when EVERY element is truthy - all three numbers are positive, so True. One failure would make it False (and it stops checking there).

all()any()

Q21. medium

What is the output of: print(sorted([3, 1, 2], reverse=True))

  1. A [1, 2, 3]
  2. B [3, 2, 1]
  3. C [2, 1, 3]
  4. D None

Answer: B — [3, 2, 1]

sorted() with reverse=True sorts descending: [3, 2, 1]. Comprehensions often feed into sorted(): sorted([w.lower() for w in words]).

sorted()reverse parameter

Q23. medium

Convert with a comprehension: strings = ["1", "2", "3"] into numbers [1, 2, 3]

strings = ["1", "2", "3"]
nums = [int(s) for s in strings]
print(sum(nums))   # 6
  1. A [int(s) for s in strings]
  2. B int(strings)
  3. C [s.int() for s in strings]
  4. D strings.to_int()

Answer: A — [int(s) for s in strings]

Apply int() to each element: [int(s) for s in strings]. int(strings) fails - int() can't convert a whole list at once.

Type conversionmap()

Q25. medium

What is the output of: print([i for i in range(20) if i % 2 == 0 if i % 3 == 0])

[i for i in range(20) if i % 2 == 0 if i % 3 == 0]
# same as: if i % 6 == 0
  1. A [0, 6, 12, 18]
  2. B [6, 12, 18]
  3. C [0, 2, 3, 4, 6...]
  4. D SyntaxError

Answer: A — [0, 6, 12, 18]

Multiple if clauses act like AND - keep numbers divisible by 2 AND by 3 (i.e. by 6): 0, 6, 12, 18. Equivalent to one if with and.

Multiple filters

Q27. medium

Marks: {"Ana": 92, "Ben": 45}. Which builds a list of names who PASSED (>= 50)?

marks = {"Ana": 92, "Ben": 45}
passed = [n for n, m in marks.items() if m >= 50]
print(passed)   # ['Ana']
  1. A [name for name, mark in marks.items() if mark >= 50]
  2. B [mark for mark in marks if mark >= 50]
  3. C [name for name in marks.values() if name >= 50]
  4. D marks.passed()

Answer: A — [name for name, mark in marks.items() if mark >= 50]

Iterate items() to get both name and mark, filter on the mark, collect the name: ['Ana']. Option B loops over keys (strings) and compares them to 50 - TypeError.

items()Filtering dicts

Q30. medium

Clean this data with one comprehension: names = [" ana ", "BEN ", " Cy"] -> ["Ana", "Ben", "Cy"]

names = [" ana ", "BEN ", " Cy"]
clean = [n.strip().title() for n in names]
print(clean)   # ['Ana', 'Ben', 'Cy']
  1. A [n.strip().title() for n in names]
  2. B [n.title() for n in names.strip()]
  3. C names.strip().title()
  4. D [strip(n) + title(n) for n in names]

Answer: A — [n.strip().title() for n in names]

Chain methods inside the expression: strip() removes the spaces, then title() fixes the capitalization - applied to each name. Option B calls strip() on the LIST, which doesn't exist.

Method chainingData cleaning

Hard questions (9)

Q4. hard

What is the output of: print([x * 2 for x in range(4) if x % 2 == 0])

# x in 0,1,2,3 -> keep 0,2 -> double -> [0, 4]
  1. A [0, 2, 4, 6]
  2. B [0, 4]
  3. C [2, 6]
  4. D [0, 2]

Answer: B — [0, 4]

First the filter keeps even x (0 and 2), then the expression doubles them -> [0, 4]. Filter first, transform second.

Filter + transform

Q7. hard

Where does if-ELSE go in a comprehension? result = [x if x > 0 else 0 for x in nums]

nums = [3, -1, 5]
print([x if x > 0 else 0 for x in nums])  # [3, 0, 5] - transform
print([x for x in nums if x > 0])           # [3, 5]    - filter
  1. A BEFORE the for - because with else it's a conditional EXPRESSION, not a filter
  2. B After the for, like a filter
  3. C if-else is not allowed in comprehensions
  4. D Either position works

Answer: A — BEFORE the for - because with else it's a conditional EXPRESSION, not a filter

Two different ifs! A filtering if (no else) goes AFTER the for and drops items. A conditional expression (with else) goes BEFORE the for and transforms every item. [x if x > 0 else 0 ...] keeps all items, replacing negatives with 0.

  • [x for x in nums if x > 0 else 0] is a SyntaxError.

Ternary expressionFiltering

Q11. hard

Why prefer sum(x*x for x in range(10**7)) over sum([x*x for x in range(10**7)])?

total = sum(x*x for x in range(10**7))  # memory-friendly
  1. A The first is shorter to type only
  2. B The generator version never builds a 10-million-item list in memory - values stream one by one
  3. C The list version gives a wrong answer
  4. D There is no difference

Answer: B — The generator version never builds a 10-million-item list in memory - values stream one by one

The list comprehension materializes ALL 10 million squares in RAM before summing. The generator produces each value, hands it to sum(), and forgets it - constant memory. For large data, generators win.

GeneratorsMemory efficiency

Q13. hard

What is the output of: print([x + y for x in "ab" for y in "cd"])

# same as:
for x in "ab":
    for y in "cd":
        result.append(x + y)
  1. A ['ac', 'ad', 'bc', 'bd']
  2. B ['ac', 'bd']
  3. C ['ab', 'cd']
  4. D ['ca', 'da', 'cb', 'db']

Answer: A — ['ac', 'ad', 'bc', 'bd']

Two for clauses nest like a double loop - the FIRST for is the outer loop. For each x ('a', then 'b'), y runs through 'c', 'd': ac, ad, bc, bd.

Nested comprehensionsCartesian product

Q14. hard

How do you FLATTEN matrix = [[1, 2], [3, 4]] into [1, 2, 3, 4] with a comprehension?

matrix = [[1, 2], [3, 4]]
flat = [x for row in matrix for x in row]
print(flat)   # [1, 2, 3, 4]
  1. A [x for row in matrix for x in row]
  2. B [x for x in row for row in matrix]
  3. C [matrix for row in x]
  4. D flatten(matrix)

Answer: A — [x for row in matrix for x in row]

Read the for clauses LEFT TO RIGHT like nested loops: first 'for row in matrix' (outer), then 'for x in row' (inner). Option B is backwards - row isn't defined yet.

  • Order rule: the fors appear in the same order as in the loop version.

FlatteningNested loops

Q20. hard

Which correctly builds a 3x3 grid of zeros where rows are INDEPENDENT?

bad = [[0] * 3] * 3
bad[0][0] = 9
print(bad)    # [[9,0,0],[9,0,0],[9,0,0]] !!

good = [[0] * 3 for _ in range(3)]
good[0][0] = 9
print(good)   # [[9,0,0],[0,0,0],[0,0,0]]
  1. A grid = [[0] * 3 for _ in range(3)]
  2. B grid = [[0] * 3] * 3
  3. C Both A and B are identical
  4. D grid = [0] * 9

Answer: A — grid = [[0] * 3 for _ in range(3)]

Option B repeats a reference to the SAME row three times - changing grid[0][0] would change all three rows! The comprehension creates a fresh list each iteration, so rows are independent.

  • A classic trap when building 2D grids for games or matrices.

References2D lists

Q22. hard

In Python 3, does the loop variable of a comprehension LEAK outside? [x for x in range(3)] print(x)

[x for x in range(3)]
# print(x)   # NameError in Python 3
  1. A Yes - x is 2 afterwards
  2. B No - NameError: comprehensions have their own scope in Python 3
  3. C x becomes the whole list
  4. D x is always 0

Answer: B — No - NameError: comprehensions have their own scope in Python 3

In Python 3, comprehension variables live in their own hidden scope and vanish afterwards - print(x) raises NameError (unless x existed before). In Python 2 they leaked; this was fixed.

ScopePython 2 vs 3

Q24. hard

Which is equivalent to map(str.upper, words)?

words = ["hi", "bye"]
print(list(map(str.upper, words)))   # ['HI', 'BYE']
print([w.upper() for w in words])     # same
  1. A [str.upper for w in words]
  2. B [w.upper() for w in words]
  3. C {w.upper() for w in words}
  4. D (words.upper())

Answer: B — [w.upper() for w in words]

map(function, iterable) applies the function to each item - exactly what [w.upper() for w in words] does. Most Python style guides prefer the comprehension for readability.

map()filter()

Q29. hard

What is the output? funcs = [x**2 for x in range(3)] print(funcs[-1])

  1. A 4
  2. B 2
  3. C 9
  4. D [0, 1, 4]

Answer: A — 4

The comprehension builds [0, 1, 4] (squares of 0, 1, 2), and [-1] takes the last element: 4. Combining comprehension results with indexing is common in interview snippets.

IndexingTracing code

Practice “Comprehensions” as a quiz