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?
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).
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With