I’ll be honest, until recently, Python list comprehensions were avoided at all cost. They seemed confusing and akin to a ternary if statement gone horribly amuck. Readability of a list comprehension is tricky because there is no delimiter to segment the various elements (modify, loop, filter logic).
Simply put…

A list comprehension generates a new list by applying filters and transformations to items in a source list.

Let’s start by defining the basic list comprehension as follows

result = [new_thing for thing in your_list]

Let’s start with a simple (and very useless) example where ‘i’ is our new_thing, as described above.

your_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered = [i for i in your_list]
print(filtered)
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

You’ll note in the original definition that there is new_thing as well as thing, yet in the example, both of those arguments are simply defined as i. The reason for that is because new_thing doesn’t necessarily need to be exactly what thing is. Let’s expand the example and make it a bit more useful.

your_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered = [i * i for i in your_list]
print(filtered)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Woah! new_thing just got a lot more useful, right? As you iterate through the for loop, the element which is returned can be operated on. In this example, we multiply the value by itself.
You can do all sorts of fun operations in that field BUT (you knew that was coming) you don’t want to perform conditional logic in that section. The list comprehension syntax has a different area for that. Let’s expand our original definition:

result = [new_thing for thing in your_list if thing is worthy]

Before your thing is passed along to the new_thing modification logic, it can be filtered using conditional logic. That logic is placed after the for loop section. Confused? An example will clear that right up.

filtered = [i * i for i in your_list if i % 2]
print(filtered)
[1, 9, 25, 49, 81]

Now, only the odd numbers found in your_list will be passed along to the new_thing section.

Why Use List Comprehensions?

Now that we have an understanding of the syntax, let’s take a quick look at the logic required for the last example, without list comprehensions.

your_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
filtered = []
for i in your_list:
    if i % 2:
        filtered.append(i * i)
print(filtered)

It’s not rocket science, and certainly easy to read, but it does take up more space in your code. Is that easier to read than this?

filtered = [i * i for i in your_list if i % 2]
print(filtered)

I’ll leave that up for you to decide. Personally, the more I use list comprehensions, the easier they are to quickly solve complex filtering problems. When coupled with database, or number set filtering, they become increasingly more useful.