To all the people saying list comprehensions are bad because they are hard to understand, I beg to differ.
The only reason you might think that is because you are used to the long form version and once you get used to list comprehensions they are much much more readable and practical, because instead of drawing out the same info it is super compact. Also because it describes what you want instead of how to get what you want.
LCs are even more useful for more complex things like if you want to apply a function to transform the elements.
# generate first 10 squares
squares10 = [num * num for num in range(1,11)]
Super simple and long form version is:
>>> squares10 = []
>>> for num in range(1,11):
... squares10.append(num*num)
Way longer, easier to make a mistake, and less descriptive.
nested LCs are also fantastic and pay off even more. To give very simple example, imagine you want to generate a big list of possible names for bots or anonymous users, etc.
>>> adjectives = ["Happy", "Angry", "Hungry"]
>>> animals = ["Lion", "Zebra", "Hippo"]
>>> names = [adj + animal for adj in adjectives for animal in animals]
>>> names
['HappyLion', 'HappyZebra', 'HappyHippo', 'AngryLion', 'AngryZebra', 'AngryHippo', 'HungryLion', 'HungryZebra', 'HungryHippo']
P.S. I know there are other ways to enumerate possible combinations. This is mostly just an example, but one ting to keep in mind is that LCs are more versatile.