Note
Python - List, Tuple, and Set Comprehensions - Simplify iterable transformations
Overview of Python Comprehensions: Lists, Tuples, and Sets
List Comprehensions in Python lets you quickly generate a list from another iterable.
[<expression_1> for <variable> in <iterable> if <expression_2>]
While doing so, you can optionally perform operations on arguments going into your list and also filter them.
Remember that even though we are calling this "List Comprehensions" we can simply transform them into:
-
Tuple Comprehensions - simply replace
[]with(). Important - Even though we are calling it a "tuple" comprehension, this will create a generator. -
Set Comprehensions - simply replace
[]with{}. As you guessed, Set Comprehensions will createsetso it will delete duplicates.
There are also "Dict Comprehensions" but they have their own note since the syntax is a little different.
Consider the following examples:
my_list = [x for x in range(0, 10)]
print(my_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
This is one of the simplest examples of list comprehension.
Quick Example with Set Comprehension and Tuple Comprehension
my_set = {x**2 for x in range(0, 10) if x % 2 == 0}
print(my_set) # {0, 64, 4, 36, 16}
print(type(my_set)) # <class 'set'>
my_tuple_gen = (x for x in range(0, 10) if x % 2 == 0)
print(my_tuple_gen) # <generator object <genexpr> at 0x726b305ef100>
print(type(my_tuple_gen)) # <class 'generator'>
print(tuple(my_tuple_gen)) # (0, 2, 4, 6, 8)
As you can see, tuple / () comprehension produced a generator object. This object can be cast to tuple.
Adding Operations and Conditions
my_list = [x**2 for x in range(0, 10) if x % 2 == 0]
print(my_list) # [0, 4, 16, 36, 64]
Output:
[0, 4, 16, 36, 64]
Here, we want in our list, squares of integers that are even (are divisible by 2 without any remain) from range 0 to 10.
Splitting Comprehension Over Several Lines Might Make it More Readable
We can split this list comprehension on more than one line to make it more readable:
my_list = [x**2 # Operation on argument
for x in range(0, 10) # Iteration, for loop over iterable
if x % 2 == 0] # condition that needs to be met to pass argument to operation and later to our list
print(my_list)
Output:
[0, 4, 16, 36, 64]
Nested Comprehensions
Answering your question, yes, comprehension can be nested. And they can access variables, methods, etc. from outer scopes.
def multiply_number(number: int, multiplier: int) -> int:
return number * multiplier
custom_range = range(0, 10)
nested = [multiply_number(x, 2) for x in [x**2 for x in custom_range if x % 2 == 0] if x % 8 == 0]
print(nested) # [0, 32, 128]
nested = [multiply_number(x, 2) # operation on argument
for x in [x**2 for x in custom_range if x % 2 == 0] # for loop over iterable (in this case, other list comprehension)
if x % 8 == 0] # condition that need to be met to pass argument to operation and later to our list
print(nested) # [0, 32, 128]
Output:
[0, 32, 128]
[0, 32, 128]
But try to remember that the more complicated comprehension, the harder it is to read, not by a computer but by a human. And we need to remember that we are also writing code for other developers. We are humans too!
Key Points to Remember about List, Tuple, and Set Comprehensions
-
Versatility: List comprehensions can be easily adapted for tuple (generator) and set comprehensions by changing the brackets.
-
Readability: Although comprehensions are short, they are harder to read. Aim for clarity, especially in nested comprehensions (or simply avoid them).
-
Automatic Deduplication in Sets: Set comprehensions automatically remove duplicates, which can be useful in certain tasks.
I hope you found this helpful! If you have any feedback, questions or requests, please reach out to me through Contact page!