List Comprehensions
First, imagine you're a chef, and you're making a list of dishes. If you simply want to make a list of square dishes, you'd go through a menu and note the square of each dish's number:
[x**2 for x in range(1, 6)]
This is like saying, "For each dish number x from 1 to 5, put x squared onto my list."
Now, suppose you only want to note the square of the even-numbered dishes. This is where you add a condition, like a filter:
[x**2 for x in range(1, 6) if x % 2 == 0]
Here's what's happening:
- You're still going through the menu (the for x in range(1, 6) part).
- But now, before you add the squared dish number to your list, you check if the dish number is even (if x % 2 == 0), meaning going through the entire list.
If it passes the check, Python keeps the values, because these are the ones where x % 2 == 0 is True, then square it and add it to your list. If it doesn't, you skip it. This is straightforward because it's just a filtering operation.
Now, let's say you have a new rule. If the dish number is even, you still want its square, but if it's odd, you want to subtract 1 from it instead. So, for each dish, you either square it or subtract 1 depending on whether it's even or odd.
If you were writing this without list comprehension, it would look something like this:
result = []
for x in range(1, 6):
if x % 2 == 0:
result.append(x**2)
else:
result.append(x - 1)
In list comprehension, this "choice" (the if-else) needs to be right at the front because you need to tell Python what value to add to the list. You're essentially saying, "For each dish number, decide right away what you're adding to the list, either the x**2 or x - 1".
[x**2 if x % 2 == 0 else x - 1 for x in range(1, 6)]
Why does the if-condition work after the loop, but if-else goes before?
When you write the if condition after the loop, you're saying, "Only consider this item if it meets the condition". Python doesn't need to know what happens if it fails because you're only telling it what to do when it passes.
Example:
[x**2 for x in range(1, 6) if x % 2 == 0]
Here, you're telling Python, "Only consider x if x % 2 == 0, and then square it".
With an if-else, you're not filtering anymore. Instead, you're deciding which value to add to the list, so you have to place this logic before the loop because it's part of the expression that determines the list's content.
Example:
[x**2 if x % 2 == 0 else x - 1 for x in range(1, 6)]
Here, you're telling Python, "For each x, decide between x**2 and x - 1 based on whether x is even or odd, then add that result to the list".
Why can't the if go before the loop?
In Python, when you use a simple if statement in list comprehension, it's always considered a filter. Filters work after the loop because they are a separate step, first, generate the items, then decide which ones to keep.
An if-else, however, is part of the generation step. You're deciding what value to create for each iteration, which is why it comes before the loop. Python needs to know immediately what value to work with before it can decide whether or not to keep it.
Wrapping it all up:
- Filter (if): Goes after the loop because it decides which items to include after they've been generated. Python first loops through the entire iterable (range(1, 6)), considering each value one by one. On the values that passed the filter, Python then applies the operation and adds them to the list.
- Choice (if-else): Goes before the loop because it decides what value to generate for each item. Python iterates over the entire iterable (range(1, 6)), considering each value one by one. Depending on whether the condition is True or False, Python performs either the operation after the if or the operation after the else. The result of the operation (either from the if or the else) is immediately added to the list.
In summary, when you're filtering, the filtering happens before the operation is applied, but during the loop. Python checks each value with the if condition and only applies the operation to those that pass.
This is why the if statement comes after the loop in the syntax, it acts as a gatekeeper, letting only the values that pass through to have the operation performed on them.
When you use an if-else statement in a list comprehension, Python performs the operation (either the if or the else part) on each value as it loops through the iterable. This happens at each step in the loop, without any filtering.