Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to format list and dictionary comprehensions

Tags:

python

List and dictionary comprehensions are powerful and fast, but they can be hard to read. My mental read buffer quickly fills up, especially when they’re deeply nested. Is there a way to make these more readable?

like image 625
highpost Avatar asked Jun 05 '13 23:06

highpost


People also ask

What is list and dictionary comprehension with syntax?

Dictionary comprehensionsThey provide an elegant method of creating a dictionary from an iterable or transforming one dictionary into another. The syntax is similar to that used for list comprehension, namely {key: item-expression for item in iterator}, but note the inclusion of the expression pair (key:value).

What are list and dictionary comprehensions in Python?

A Comprehension is an elegant way of constructing a list or dictionary in Python. It allows us to loop through existing data and filter it to create a list or dictionary, or we can even loop through a sequence that we generate and make a list or dictionary from that sequence.

What is a dictionary comprehension?

Dictionary comprehension is a method for transforming one dictionary into another dictionary. During this transformation, items within the original dictionary can be conditionally included in the new dictionary and each item can be transformed as needed.


2 Answers

You’re right. ;) They can be hard to read, which can also make them hard to compose and debug. Let’s take the following example dict comprehension:

current_team = dict((k,v) for k,v in list(team.items()) for player in v[‘player’] if player['year'] == 2013)

Too many years of C and Java programming have made this difficult for me to read. The comprehension is logically broken into different parts, but I still need to really stare at it to decompose it.

The key thing to remember is that a comprehension is an expression, not a statement. So you can surround the expression with parens and then use implicit line joining to add line breaks that organize the expression based on its nesting levels:

current_players = (dict((k,v)
    for k,v in list(team.items())
        for player in v['player']
            if player['year'] == 2013))

Here it becomes more clear that the “the last index varying fastest, just like nested for loops.”

You can even add blank lines and comments:

current_players = (dict((k,v)            # dict comprehension:

    for k,v in list(team.items())        #   let’s filter the team member dict...
        for player in v['player']        #   for players...
            if player['year'] == 2013))  #   who are playing this year

One note of caution: the Python Language Reference says that “the indentation of the continuation lines is not important.” So you can use any form of indentation to improve readability, but the interpreter won’t do any extra checking.

like image 187
highpost Avatar answered Nov 05 '22 22:11

highpost


Another approach is to keep the power of comprehensions, but build on generators upon generators to remove the nesting then use the builtin list/set/dict etc... - something similar to:

{k:v for k, v in enumerate(range(10)) if v % 2 == 0}

Could be broken out to:

with_idx = enumerate(range(10))
is_even = (el for el in with_idx if el[1] % 2 == 0)
as_dict = dict(is_even)

Which is actually way more verbose but if you apply similar logic to the nested levels, then does actually make more sense.

like image 21
Jon Clements Avatar answered Nov 05 '22 23:11

Jon Clements