Covered: list comprehensions, string comprehensions, dictionary comprehensions, own class comprehensions
List comprehensions
List comprehensions are a pythonic way of generating lists from existing lists. These are generally faster than using a for loop and doing .append() because that involves some overhead.
In the simplest form, a list comprehension can be written as:
[ <expression> for <item> in <series> ]
The square brackets mean that the result should be a new list. Expression can be anything, ex. [ factorial(number) for number in numbers ].
Filtering items in comprehensions
Filtering is done by using conditional statements. When we are using just the if statement, we can write the comprehension as:
[ <expression> for <item> in <series> if <Boolean expression> ]
ex. [ (number, factorial(number)) for number in numbers if number >= 0 and number % 2 == 0]
Alternative execution can be done using an else statement inside the comprehension as well. In that case the “full” list comprehension becomes:
[ <expression1> if <condition> else <expression2> for <item> in <series> ]
Yes, the conditional structure is now before the for keyword.
A real example of list comprehensions in action:
class ExamResult:
def __init__(self, name: str, grade1: int, grade2: int, grade3: int):
self.name = name
self.grade1 = grade1
self.grade2 = grade2
self.grade3 = grade3
def __str__(self):
return (f'Name:{self.name}, grade1: {self.grade1}' +
f', grade2: {self.grade2}, grade3: {self.grade3}')
def best_results(results: list[ExamResult]):
return [max(result.grade1, result.grade2, result.grade3) for result in results]
if __name__ == "__main__":
result1 = ExamResult("Peter",5,3,4)
result2 = ExamResult("Pippa",3,4,1)
result3 = ExamResult("Paul",2,1,3)
results = [result1, result2, result3]
print(best_results(results))Another example:
class LotteryNumbers:
def __init__(self, week_number: int, numbers: list[int]):
""" Constructs the LotteryNumbers object for a given week number with a list of correct lottery numbers"""
self.__week_number = week_number
self.__numbers = numbers
def number_of_hits(self, numbers: list):
""" Returns the number of correct entries in the given list """
return len([number for number in numbers if number in self.__numbers])
def hits_in_place(self, numbers: list[int]):
""" Takes a list of seven integers and returns a new list with only those items which match the week's correct numbers """
return [number if number in self.__numbers else -1 for number in numbers]
if __name__ == "__main__":
week5 = LotteryNumbers(5, [1,2,3,4,5,6,7])
my_numbers = [1,4,7,11,13,19,24]
print(week5.number_of_hits(my_numbers))
week8 = LotteryNumbers(8, [1,2,3,10,20,30,33])
my_numbers = [1,4,7,10,11,20,30]
print(week8.hits_in_place(my_numbers))More comprehensions
Comprehensions work on any series of items, such as strings, tuples, dictionaries, and even your own classes if they’re iterable.
An “full” example of string comprehension:
def filter_forbidden(string: str, forbidden: str):
return "".join([character for character in string if character not in forbidden])
if __name__ == "__main__":
sentence = "Once! upon, a time: there was a python!??!?!"
filtered = filter_forbidden(sentence, "!?:,.")
print(filtered)Comprehensions also work with dictionaries, as mentioned before. If you enclose the comprehension inside curly brackets, the result would be a dictionary comprehension. Keep in mind that for a dictionary you need to provide the key and value pairs, and it’s the same for comprehensions. The general syntax looks like this:
{ <key expression> : <value expression> for <item> in <series> } if you’re not using an else.
ex. { word: words_list.count(word) for word in words_list if words_list.count(word) >= lower_limit }
NOTE: generator comprehensions are discussed in Functions
When to use
The general consensus (even in Google’s style guide) is that list comprehensions are a concise and efficient way to create iterators. But they should not be used if multiple for clauses are present or filter statements (if) are present, i.e. in nested comprehensions. “Optimise for readability, not conciseness.”