Sign in to your Python Morsels account to save your screencast settings.
Don't have an account yet? Sign up here.
When should you not use a list comprehension in Python?
We have a list of strings that represent fruits:
>>> fruits = ["lime", "blueberry", "watermelon", "pear", "jujube"]
And we have a list comprehension that prints out each of these fruits on their own line:
>>> [print(fruit) for fruit in fruits]
lime
blueberry
watermelon
pear
jujube
[None, None, None, None, None]
While you can use list comprehension for printing, you probably shouldn't do this.
While this list comprehension did print, it also gave us back a list of None
values.
Our list comprehension created a list of five None
values because the purpose of a list comprehension is to build a new list and that's exactly what we've done.
The thing that we're appending to our new list is the return value of print (which is the default function return value of None
).
list comprehensions are specifically for looping over some existing iterable and making a new list out of it.
for
loops are a general purpose looping toolA better way to print out everything in a list is to use a for
loop:
>>> for fruit in fruits:
... print(fruit)
...
lime
blueberry
watermelon
pear
jujube
A for
loop is useful for looping over an iterable and performing an action.
for
loops are a general purpose tool: they're for looping over an iterable to do anything.
List comprehensions are a special purpose tool: they're just for looping over an iterable in order to build up a new list.
When I glance at this code, I assume that the purpose of this line is to build up a new list:
>>> [print(fruit) for fruit in fruits]
But deceptively the purpose of this code is not to build up a new list, the purpose is to print.
Don't use a list comprehension unless you care about building up a new list.
What if the list you're building is basically the same thing as the iterable you're building it from?
Take this list comprehension for example:
>>> fruit_counts = [(n, fruit) for (n, fruit) in enumerate(fruits, start=1)]
This list comprehension takes the return value of enumerate
, loops over it, and unpacks it into a 2-item tuple and then repacks it into the same tuple.
This list comprehension is building up a list of all the contents that enumerate
gives us as we loop over it:
>>> fruit_counts
[(1, 'lime'), (2, 'blueberry'), (3, 'watermelon'), (4, 'pear'), (5, 'jujube')]
That comprehension above is essentially the same as this comprehension:
>>> fruit_counts = [x for x in enumerate(fruits, start=1)]
We're taking each of the items we get from calling enumerate
and storing them in a new list.
Whenever you see a list comprehension in the format:
>>> [x for x in some_iterable]
That comprehension is looping over an iterable and turning it into a new list without changing anything at all. But there's a better way to do that in Python!
Instead of using a list comprehension we can use the list constructor:
>>> fruit_counts = list(enumerate(fruits, start=1))
The list constructor accepts an iterable and it will make a new list out of that iterable (storing each of the items it finds as it loops over that iterable).
>>> fruit_counts
[(1, 'lime'), (2, 'blueberry'), (3, 'watermelon'), (4, 'pear'), (5, 'jujube')]
Whenever your comprehension can be boiled down to x for x in something
:
>>> new_list = [x for x in some_iterable]
You should probably use a list constructor instead:
>>> new_list = list(some_iterable)
The list constructor is a little bit easier to read at a glance than a list comprehension.
If I see this in some code:
fruit_counts = [(n, fruit) for (n, fruit) in enumerate(fruits, start=1)]
My brain will need to parse that line for a moment to figure out what that comprehension does.
Whereas when I see a list constructor:
fruit_counts = list(enumerate(fruits, start=1))
My brain immediately thinks, "oh we're taking the return value of enumerate
and turning it into a list".
Don't use a list comprehension if you don't care about building up a new list. And even if you do care about building up a new list, there might be a shorter way to do it. For example, the list constructor is a way to take an iterable and copy that iterable into a new list (without changing anything and without filtering anything down).
Need to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
In Python it's very common to build up new lists while looping over old lists. Partly this is because we don't mutate lists very often while looping over them.
Because we build up new lists from old ones so often, Python has a special syntax to help us with this very common operation: list comprehensions.
To track your progress on this Python Morsels topic trail, sign in or sign up.
Sign in to your Python Morsels account to track your progress.
Don't have an account yet? Sign up here.