¿Sintaxis de comprensión inconsistente?

Me tropecé con lo que parece ser un defecto en la syntax de python, o de lo contrario me estoy perdiendo algo.

Mira esto:

[x for x in range(30) if x % 2 == 0] 

Pero esto es un error de syntax:

 [x for x in range(30) if x % 2 == 0 else 5] 

Si tienes una cláusula else , tienes que escribir:

 [x if x % 2 == 0 else 5 for x in range (30)] 

Pero esto es un error de syntax:

 [x if x %2 == 0 for x in range(30)] 

¿Qué me estoy perdiendo? ¿Por qué es esto tan inconsistente?

Estás mezclando la syntax aquí. Hay dos conceptos diferentes en juego aquí:

  • Lista de syntax de comprensión. Aquí if actúa como un filtro; Incluya un valor en la iteración o no. No hay else , ya que ese es el caso de “no incluir” ya.

  • Una expresión condicional . Esto siempre debe devolver un valor, ya sea el resultado de la expresión ‘true’ o la expresión ‘false’.

La diferencia entre los dos es que el final if en el primero forma parte de la syntax de comprensión de lista , mientras que if-else es el operador condicional, no una parte de la syntax de comprensión de lista, ya que es una expresión que se permite en Esa parte de una lista de comprensión.

La syntax para el operador condicional es la siguiente:

 x if condition1 else y 

Esto devuelve el valor de la expresión que se evalúa, por lo que parece que “funciona” para su caso, aunque evalúa todo el tiempo y devuelve siempre, que es la diferencia clave entre los dos.

Mientras tanto, para la comprensión de la lista, comprueba si la condición se aplica o no, y no agrega eso en la nueva lista creada si la condición no se evalúa como verdadera de acuerdo con el procedimiento de Verificación del Valor de la Verdad , ni None ni nada más.

Compare lo siguiente (tomando un ejemplo de PEP202 ):

 a = [i if i % 2 == 0 else None for i in range(20)] b = [i for i in range(20) if i % 2 == 0] 

a sería

 [0, None, 2, None, 4, None, 6, None, 8, None, 10, None, 12, None, 14, None, 16, None, 18, None] 

mientras b sería

 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 

que no es lo mismo en absoluto, ya que no importa cuál sea el resultado, aún lo agregará si no hay ninguna parte de la lista de comprensión .

¿Qué me estoy perdiendo?

La siguiente es una operación ternaria (también conocida como “expresión condicional” en el lenguaje de python)

 x if some_boolean else y 

Esto se evalúa como se lee: si some_boolean es True , dame x , de lo contrario dame y.

No confunda esto con la syntax de comprensión:

 (expression) for (iteration variable) in (iterable) [if (filter)] 

Una expresión condicional puede ir a la parte (expresión). No tiene nada que ver con la parte opcional if (filter) .