Skip to content

Latest commit

 

History

History
115 lines (78 loc) · 3.7 KB

comprehensions.md

File metadata and controls

115 lines (78 loc) · 3.7 KB

Comprehensions [Readability, Performance]

What is it?

In Python, comprehensions are a block of code that can generate a sequence or filter/apply an operation to an existing sequence. These are considered pythonic, as opposed to using for loops to generate lists. Comprehensions are preferred over for-loops and map/filter, where possible and feasible. There are 3 types of comprehensions.

Detectors

List comprehension

Not pythonic

Here is a piece of code that takes a list of numbers and filters out odd numbers.

numbers = [1, 2, 3, 4, 5, 6]
even_numbers = []

for num in numbers:
    if num % 2 == 0:
        even_numbers.append(num)

>>> [2, 4, 6]

While this may be accepted in other languages, in Python this is considered not pythonic. There is a more concise way to do this.

Pythonic

numbers = [1, 2, 3, 4, 5, 6]
even_numbers = [ num for num in numbers if num % 2 == 0 ]

>>> [2, 4, 6]

The list comprehension saved ~3 lines of code in this context, and it is also more readable and concise. We could also do this in-place if we wanted to (i.e not create a separate even_numbers variable).

In fact, if we make the input size bigger we notice that list comprehension is faster as well.

@timer
def unpythonic_function():
    numbers = range(100000000)
    even = []
    
    for num in numbers:
        if num % 2 == 0:
            even.append(num)

    return even

>>> "Function 'unpythonic_function' took 6.257403173000057 seconds to complete."

@timer
def pythonic_function():
    numbers = range(100000000)
    even = [ num for num in numbers if num % 2 == 0 ]

    return even

>>> "Function 'pythonic_function' took 5.190925324001 seconds to complete."

Here is another example where we want to square every number in a list.

# Unpythonic
numbers = [1, 2, 3, 4, 5, 6]
numbers_squared = []

for num in numbers:
    numbers_squared.append(num**2)

# pythonic
numbers_squared = [num**2 for num in numbers]

Dict comprehension

This is similar to list comprehensions, except the data structure is a dict. The syntax is familiar as well.

numbers_squared = { x: x**2 for x in numbers }

Set comprehension

This is also similar to list comprehensions, except the resulting data structure is a set. The advantage of sets is the set operations as well as the property that sets can only have unique elements.

numbers_squared = { x**2 for x in numbers }

Generator expressions

Please see generators.


References

[1] PEP 202 -- List Comprehensions
[2] Python docs -- List Comprehensions
[3] PEP 274 -- Dict Comprehensions
[4] Python docs -- Dict Comprehensions
[5] Python docs -- Set Comprehensions

Books that mention this topic:

[6] Python Tricks: A Buffet of Awesome Python Features by Dan Bader
[7] Effective Python: 90 Specific Ways to Write Better Python by Brett Slatkin
[8] Python Cookbook, Third Edition by David Beazley and Brian K. Jones
[9] Writing Idiomatic Python 3 by Jeff Knupp
[10] The Little Book of Python Anti-Patterns by QuantifiedCode