Comprehensions are constructs that allow new sequences to be built from other sequences. Generally when we have to create new list from existing list, we follow these steps.

  • Instantiate a new empty list.
  • Iterate through each item in existing list and process it.
  • Append the processed output in new list.

Lets have an example of creating a list of squares from list of numbers.

Using general for-loop

In this approach we iterate through list and append squared number in new list.

Using Comprehensions

In Comprehensions, All steps –for loop and processing/output expression are same but we squash multi-line code into single one.

As seen in example above, It consist of square brackets ([]) with an expression followed by a for loop. Here square bracket tells that final output is a list. number*number is an output expression for each number in existing_list. From this understanding, we can make general template for list comprehension as:

output_expression in above template can be any valid python expression which may or may not contain element from existing_iterable. Also, existing_iterable in above expression doesn’t need to be a list only it can be any Iterable like Dictionary, Set ,Tuple or custom Iterable.

See Also: Iterable And Iterator In Python.

There is another interesting feature in Comprehensions –condition for evaluation of output_expression during iteration. For example, If we want square of only even number in above problem then.

Square is generated for only even numbers. Its because output_expression( number*number) is evaluated for only those number with property/condition number%2==0. This could be more clearly explained with:

With condition, we can define template as.

Like list comprehensions we can use same methodology to create Dictionary and Set. Once we are comfortable with list comprehensions then we can easily use comprehensions to generate other sequence.

Dictionary Comprehensions

Its used in same way as list comprehensions. Lets start with defining template for Dictionary comprehensions.

This template is for creating new dictionary from existing dictionary. Here, Iterating over existing_dict.items() gives tuple of (Key, Value). we are unpacking it and assigning it to key,value in our code. After that, for each key,value pair in existing dictionary, new key( result of key_expression) and its value(result of key_expression) pair is added in output_dict. Without using comprehensions, creating dictionary could be done as:

And with comprehensions:

In This example we left key as it was in existing_dict and incremented value by 10 to make new_dict.

Like before, we can use any Iterable in place of existing_dict.items() in above template and add conditions as well.

Set Comprehensions

They are almost same as list comprehensions. If we replace square brackets with braces then it becomes set comprehension.

Apart from these, there is another method for creating sequence called Generator Comprehensions which we will talk about in our next post.

Performance Improvements

Comprehensions implement almost same steps as full-fledged for loop shown above. But, Comprehensions are optimized for interpreter which makes it faster. If we examine our simple example from list comprehensions with timeit function then we can compare the difference.

efficiency-of-list-comprehension

Here we can see that List comprehension is around 20% faster than for-loop implementation.

Bonus Point: Nested Comprehension

Suppose we are required to create list that looks like [ [...], [...], [...] ]Then one way to get such nested list is by using nested for loop:

What happens here is:

  1. We defined a outer_list.
  2. empty list is appended on outer_list.
  3. Second loop populates appended inner list with values of j which is range(5).
  4. Step 2 and 3 goes on for every value of i which is range(5) or [0,1,2,3,4]

To get the same list using list comprehensions, we have to make comprehension expression[output_expression for element in existing_iterable] as output_expression of another expression.

In above example [j for j in range(5)] returns a list [0,1,2,3,4] and this expression is called five times for every value of i (because of range(5)). Which gives us outer_list with length five which have each element of list type with length 5.