Python comprehensions

Initially introduced by Barry Warsaw on PEP-202, comprehensions became part of the Python language in version 2.0 almost twenty years ago. This language feature enables a beautiful and convenient way to work with iterables. By using comprehensions the code is written in a more declarative and concise way. I think of it as an elegant way of Python’s for implementing a well-known Mathematics notation: { x2 | x ∈ ℕ }.

Let’s look at a code example. The lines of code below add the square numbers from 0 to 9 to a list and print them.

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

List comprehensions

The same functionality can be re-written using list comprehensions with the following syntax: [ expression for * *element** in iterable ]

squares = [x ** 2 for x in range(10)]
print(squares)

Using conditionals statements with list comprehensions

The initial presented code is now modified below using a conditional statement that only adds the even square numbers to the list.

squares = []
for x in range(10):
    if (x % 2 == 0):
        squares.append(x ** 2)
print(squares)

This can be re-written with the following syntax: [ expression for element in iterable if condition ]

squares = [x ** 2 for x in range(10) if (x % 2 == 0)]
print(squares)

Dictionary comprehensions

In PEP-274 a proposal for similar syntactical extension for dictionary objects instead of lists is introduced. This one is called “Dictionary Comprehension”. And you can see an example below using a conditional statement.

squares = {x: x**2 for x in range(10) if (x % 2 == 0)}
print(squares)

Set comprehensions

A set is an unordered and mutable collection of items. All its elements are unique (no duplicates) and immutable. Set comprehensions are created the same way as dictionary comprehensions.

numbers = [0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 9, 9]
squares = {x**2 for x in numbers}
print(squares)

Generator comprehensions

They are similar to the examples above. The main difference is that they do not allocate memory for the expected type but generate one item at a time. This results in better memory usage efficiency. See also PEP-289.

squares = (x**2 for x in range(10) if x % 2 == 0)
print(squares)
for s in squares:
    print(s)

TLDR

Comprehensions are in my humble opinion an awesome feature of Python, supported in both versions 2.x. and 3.x. As you can see, they provide a clean and concise way to avoid nested loops, lambda functions or even filter() or/and map functions.