Python Comprehension

A guided tour and quick start.

Image for post
Image for post
Photo by Sharon McCutcheon from Pexels

If you ( like me ) are new to python and/or comprehension I hope this short tutorial will get you up to speed. In a nutshell, comprehension is a way to write concise ( short and effective) python code.

Much of comprehension in python deals with how you speak the language and much like your real language, you can say something with a lot of words (verbose) or say a lot with a few words (succinct).

Even if you prefer verbose code ( I sometimes do ), concise code is widely used, so if you want to read others code it pays to learn about it, let’s start with a plain vanilla verbose example so we have something to work with.

""" Here we are simply populating a list """boxODonuts = []
FLAVORS = ['Glaze', 'Chocolate', 'Vanilla', 'Cinnamon']
for flavor in FLAVORS:
boxODonuts.append(flavor + ' donut')
print(boxODonuts)OUTPUT:
['Glaze donut', 'Chocolate donut', 'Vanilla donut', 'Cinnamon donut']
Image for post
Image for post

Let’s now do something to our donuts, like sample all of them

""" creating a temporary list, iterating over a list, doing something to each item
and replacing the original list with the modified elements"""
tempBox = []
for donut in boxODonuts:
tempBox.append('Bitten ' + donut)
boxODonuts = tempBox
print(boxODonuts)['Bitten Glaze donut', 'Bitten Chocolate donut', 'Bitten Vanilla donut', 'Bitten Cinnamon donut']
Image for post
Image for post

One last addition to our example is to encapsulate operations into a function, let’s say after sampling the donuts we decide we liked them all and we want to eat half of each, let’s do that :

""" Here we apply a simple function to each element of a list, 
add them to a temporary copy and replace the original list"""
def eathalf(donut):
return 'Half eaten ' + donut
tempBox = []
for donut in boxODonuts:
tempBox.append(eathalf(donut))
boxODonuts = tempBox
print(boxODonuts)['Half eaten Bitten Glaze donut', 'Half eaten Bitten Chocolate donut', 'Half eaten Bitten Vanilla donut', 'Half eaten Bitten Cinnamon donut']
Image for post
Image for post

Python provides a built-in function to apply a function to a list or iterable ( list,dict, etc ) called map() .

Image for post
Image for post

Let’s start with a fresh box o donuts and add sprinkles with map:

""" Applies a function to a list with map """boxODonuts = ['Glaze donut', 'Chocolate donut', 'Vanilla donut', 'Cinnamon donut']def sprinkle(donut):
return 'Sprinkled ' + donut
# Note that map returns a map object, we still need to convert it to a list to replace out original box..tempBox = map(sprinkle, boxODonuts)
boxODonuts = list(tempBox)
print(boxODonuts)['Sprinkled Glaze donut', 'Sprinkled Chocolate donut', 'Sprinkled Vanilla donut', 'Sprinkled Cinnamon donut']
Image for post
Image for post
⚠️ map() has fallen out of use for many cases in favor of comprehension, but since at this point we are building towards understanding comprehension, it is helpful to know about it, there's a lot of code out there that uses it, so it's also good to know, you can read more about it in this Stack Overflow question:List comprehension vs Map

A lambda is an anonymous ( no name ) function that is meant to be a simple drop in, you can have many arguments but only one expression, so that in itself limits what you can do with them.

Image for post
Image for post

To understand lambdas, I recommend you start with a regular function and convert it to a lambda, here’s one such example:

""" Comparison of a regular function and a lambda function, note that we are still naming the lambda function for explanatory purposes"""Regular function:def fillDonut(donut):
return 'Creme Filled ' + donut
Lambda (this one is named though):fillDonut = lambda donut: 'Creme Filled ' + donut

Using a lambda is identical to using a regular function:

""" Using either of the above functions should give you the same result"""Donuts = ['Glaze donut', 'Chocolate donut', 'Vanilla donut', 'Cinnamon donut']tempBox = []
for donut in Donuts:
tempBox.append(fillDonut(donut))
boxODonuts = tempBox
print(boxODonuts)['Creme Filled Glaze donut', 'Creme Filled Chocolate donut', 'Creme Filled Vanilla donut', 'Creme Filled Cinnamon donut']

It might seem that we are not really saving words here, but we have all the elements to produce a short and powerful sentence with what we have reviewed, consider the following rewrite of our last case:

""" One sentence replaces a for loop and a function definition """Donuts = ['Glaze donut', 'Chocolate donut', 'Vanilla donut', 'Cinnamon donut']boxOCremeFilledDonuts = list(map(lambda donut: 'Creme Filled ' + donut, Donuts))print(boxODonuts)['Creme Filled Glaze donut', 'Creme Filled Chocolate donut', 'Creme Filled Vanilla donut', 'Creme Filled Cinnamon donut']
Image for post
Image for post
⚠️ Most likely you will find and use lambdas with numerical operations (not donuts), for instance something like this:sumTwo = lambda x,y: x + yprint(sumTwo(5,4)) #9
print(sumTwo(2,3)) #5
or in conjunction with other built in functions, sorted() and casefold() in this case:flavors = ["Vanilla", "chocolate", "Maple", "Cinnamon", "bacon"]
print(sorted(flavors, key=lambda f: f.casefold()))
# ['Bacon', 'Chocolate', 'Cinnamon', 'Maple', 'Vanilla']# without casefold() sorting doesn’t quite work, the lambda iterates over the flavors list and ignores the case, in comparison:print(sorted(flavors))# ['Cinnamon', 'Maple', 'Vanilla', 'bacon', 'chocolate']Try rewriting these into regular functions if you don’t get them at first, and if writing them yourself, consider not overusing them.

And finally there’s comprehension which builds on the preceding concepts to make complex statements even shorter and to some more readable, let’s start with a simple form of list comprehension.

""" Using comprehension to modify and populate a list, same as our first example, we'll compare them in a second"""FLAVORS = ['Glaze', 'Chocolate', 'Vanilla', 'Cinnamon']boxODonuts = [flavor + ' donut' for flavor in FLAVORS]print(boxODonuts)['Glaze donut', 'Chocolate donut', 'Vanilla donut', 'Cinnamon donut']
Image for post
Image for post
""" For comparison, here's both """""" Without comprehension: """boxODonuts = []
for flavor in FLAVORS:
boxODonuts.append(flavor + ' donut')
""" With comprehension: """boxODonuts = [flavor + ' donut' for flavor in FLAVORS]
Image for post
Image for post

As promised, we’ve said a lot with little code, but at the cost of learning how to say it.

Comprehension doesn’t stop there, we can explore more complex forms, here we add a conditional to exclude from our original list:

Image for post
Image for post
""" Using comprehension and a conditional, no Cinnamon donuts here """FLAVORS = ['Glaze', 'Chocolate', 'Vanilla', 'Cinnamon']boxODonuts = [flavor + ' donut' for flavor in FLAVORS if flavor != 'Cinnamon']print(boxODonuts)['Glaze donut', 'Chocolate donut', 'Vanilla donut']
Image for post
Image for post

An alternative method for using conditionals in comprehension is to put them up front, this way you can use if/else and branch :

Image for post
Image for post
""" We ran out of most flavors, we can only make Glaze Donuts,the rest will have to be muffins ( the lesser pastry )"""FLAVORS = ['Glaze', 'Chocolate', 'Vanilla', 'Cinnamon']boxOPastries = [(flavor + ' Donut') if flavor == 'Glaze' else (flavor + ' Muffin' )for flavor in FLAVORS ]print(boxOPastries)['Glaze Donut', 'Chocolate Muffin', 'Vanilla Muffin', 'Cinnamon Muffin']
Image for post
Image for post

One last thing worth mentioning before wrapping things up, is that the output of list comprehension can be a complex function, this allows you the flexibility of mixing short and long statements while generating a list:

Image for post
Image for post
""" Here we are throwing everything at our donuts, but by separating the function and using comprehension we can save a few words"""FLAVORS = ['Glaze', 'Chocolate', 'Vanilla', 'Cinnamon']def complexDonut(flavor):
cremefilled = flavor + ' creme filled'
sprinkled = cremefilled + ' sprinkled '
donut = sprinkled + 'donut'
return donut
boxODonuts = [complexDonut(flavor) for flavor in FLAVORS ]print(boxODonuts)['Glaze creme filled sprinkled donut', 'Chocolate creme filled sprinkled donut', 'Vanilla creme filled sprinkled donut', 'Cinnamon creme filled sprinkled donut']Note: You can also use an outside lambda definition ( inside the list comprehension it's somehow meaningless ).
Image for post
Image for post
Photo by Tofros.com from Pexels

I hope this short tutorial get’s you up to speed in python comprehension, but this is just the beginning, there’s two things I would like to leave you with:

  1. When to use comprehension ? A tricky subject, I recommend you start using it in small lists or dictionaries where the functions are clear and you are replacing a for loop, something like this maybe:
""" Make 1000 random flavor donuts """allTheDonuts = [ random.choice(FLAVORS) + ' donut' for i in range(1000)]

Beyond that you should follow your teams style guide ( if working on a team ), or consider going verbose, here’s more on the subject.

2. Where to go next ? We’ve been using lists to understand comprehension, mostly because they are simple, but comprehension also works in Dictionaries, sets and iterables, additionally, some forms of derived comprehension can get complex, ( nested conditionals for instance ), but I believe you have the bases to tackle most complex cases, here’s another introduction you might find useful:

Thanks for reading !

-Keno

Written by

AI, Software Developer, Designer : www.k3no.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store