Cuando anidamos varios bucles, sigue siendo posible aplicar condiciones a todos ellos. Por ejemplo, seguimos con el mismo ejemplo que acabamos de ver:
cities = ["Madrid", "Barcelona", "Milán", "Santander"]
years = [2017, 2018, 2019, 2020]
Si quisiéramos crear una lista de tuplas formadas por las combinaciones de ciudades que empiezan por la letra "M" y los años pares, podríamos hacerlo de la siguiente forma:
[(c, y) for c in cities for y in years if c.startswith("M") if y % 2 == 0]
[('Madrid', 2018), ('Madrid', 2020), ('Milán', 2018), ('Milán', 2020)]
Tal y como vemos, las condiciones se suceden una tras otra sin añadir ningún operador lógico entre ellas.
También podríamos haber combinado ambas condiciones en una sola:
[(c, y) for c in cities for y in years if (c.startswith("M")) & (y % 2 == 0)]
[('Madrid', 2018), ('Madrid', 2020), ('Milán', 2018), ('Milán', 2020)]
Las condiciones pueden "moverse" por la expresión siempre que hagan mención a una variable que ya haya sido declarada (si leemos la expresión de izquierda a derecha):
[(c, y) for c in cities if c.startswith("M") for y in years if y % 2 == 0]
[('Madrid', 2018), ('Madrid', 2020), ('Milán', 2018), ('Milán', 2020)]
En el anterior ejemplo obtendríamos un error si intercambiásemos las dos condiciones:
try:
[(c, y) for c in cities if y % 2 == 0 for y in years if c.startswith("M")]
except:
print("Error")
Error
...pues la condición "if y % 2 == 0" se estaría ejecutando antes de declarar la variable "y".