¿Python tiene un operador condicional ternario?


Answers

Puede indexar en una tupla:

(falseValue, trueValue)[test]

test debe ser True o False .
Puede ser más seguro implementarlo siempre como:

(falseValue, trueValue)[test == True]

o puede usar el bool() incorporado bool() para asegurar un valor Boolean :

(falseValue, trueValue)[bool(<expression>)]
Question

Si Python no tiene un operador condicional ternario, ¿es posible simular uno utilizando otras construcciones de lenguaje?




¿Python tiene un operador condicional ternario?

Sí. Del archivo de gramática :

test: or_test ['if' or_test 'else' test] | lambdef

La parte de interés es:

or_test ['if' or_test 'else' test]

Entonces, una operación condicional ternaria es de la forma:

expression1 if expression2 else expression3

expression3 se evaluará de forma diferida (es decir, se evaluará solo si expression2 es falso en un contexto booleano). Y debido a la definición recursiva, puede encadenarlos indefinidamente (aunque puede considerarse un estilo incorrecto).

expression1 if expression2 else expression3 if expression4 else expression5 # and so on

Una nota sobre el uso:

Tenga en cuenta que cada if debe seguir con un else . Las personas que aprenden listas de comprensión y expresiones de generador pueden encontrar que esta es una lección difícil de aprender: lo siguiente no funcionará, ya que Python espera una tercera expresión para un else:

[expression1 if expression2 for element in iterable]
#                          ^-- need an else here

que genera un SyntaxError: invalid syntax . Por lo tanto, lo anterior es una pieza incompleta de la lógica (quizás el usuario espera una no operación en la condición falsa) o lo que puede ser intencionado es usar expression2 como un filtro - señala que el siguiente es legal Python:

[expression1 for element in iterable if expression2]

expression2 funciona como un filtro para la comprensión de la lista, y no es un operador condicional ternario.

Sintaxis alternativa para un caso más estrecho:

Puede encontrar algo doloroso escribir lo siguiente:

expression1 if expression1 else expression2

expression1 deberá evaluarse dos veces con el uso anterior. Puede limitar la redundancia si es simplemente una variable local. Sin embargo, una expresión idiomática común y performante para este caso de uso es usar or el comportamiento de atajo:

expression1 or expression2

que es equivalente en semántica. Tenga en cuenta que algunas guías de estilo pueden limitar este uso sobre la base de la claridad; sintetiza una gran cantidad de significado en muy poca sintaxis.




A menudo puede encontrar

cond and on_true or on_false

pero esto lleva a un problema cuando on_true == 0

>>> x = 0
>>> print x == 0 and 0 or 1 
1
>>> x = 1
>>> print x == 0 and 0 or 1 
1

donde se esperaría que un operador ternario normal este resultado

>>> x = 0
>>> print 0 if x == 0 else 1 
0
>>> x = 1
>>> print 0 if x == 0 else 1 
1



Se agregó un operador para una expresión condicional en Python en 2006 como parte de la Propuesta de mejora de Python 308 . Su forma difiere del operador común ?: y es:

<expression1> if <condition> else <expression2>

que es equivalente a:

if <condition>: <expression1> else: <expression2>

Aquí hay un ejemplo:

result = x if a > b else y

Otra sintaxis que se puede usar (compatible con versiones anteriores a la 2.5):

result = (lambda:y, lambda:x)[a > b]()

donde los operandos son evaluados perezosamente .

Otra forma es indexar una tupla (que no es coherente con el operador condicional de la mayoría de los otros idiomas):

result = (y, x)[a > b]

o diccionario explícitamente construido:

result = {True: x, False: y}[a > b]

Otro método (menos confiable) pero más simple es usar and y / or operadores:

result = (a > b) and x or y

sin embargo, esto no funcionará si x sería False .

Una solución posible es hacer listas y , o tuplas, como se muestra a continuación:

result = ((a > b) and [x] or [y])[0]

o:

result = ((a > b) and (x,) or (y,))[0]

Si está trabajando con diccionarios, en lugar de utilizar un condicional ternario, puede aprovechar get(key, default) , por ejemplo:

shell = os.environ.get('SHELL', "/bin/sh")

Fuente: ?:




In [1]: a = 1 if False else 0

In [2]: a
Out[2]: 0

In [3]: b = 1 if True else 0

In [4]: b
Out[4]: 1



expresión1 si condición else expresión2

>>> a = 1
>>> b = 2
>>> 1 if a > b else -1 
-1
>>> 1 if a > b else -1 if a < b else 0
-1



Para Python 2.5 y posterior hay una sintaxis específica:

[on_true] if [cond] else [on_false]

En las Pythons más antiguas, no se implementa un operador ternario, pero es posible simularlo.

cond and on_true or on_false

Sin embargo, existe un problema potencial, que si se evalúa como True y on_true evalúa como False , se devuelve on_true lugar de on_true . Si desea este comportamiento, el método es correcto; de lo contrario, use esto:

{True: on_true, False: on_false}[cond is True] # is True, not == True

que puede ser envuelto por:

def q(cond, on_true, on_false)
    return {True: on_true, False: on_false}[cond is True]

y usado de esta manera:

q(cond, on_true, on_false)

Es compatible con todas las versiones de Python.




Sí.

>>> b = (True if 5 > 4 else False)
>>> print b
True



Más un consejo que una respuesta (no es necesario que repita lo obvio por enésima vez), pero a veces lo uso como un atajo de línea en tales construcciones:

if conditionX:
    print('yes')
else:
    print('nah')

, se convierte en:

print('yes') if conditionX else print('nah')

Algunos (muchos :) pueden fruncir el ceño como unpythonic (incluso, ruby-ish :), pero personalmente lo encuentro más natural, es decir, cómo lo expresarías normalmente, y un poco más atractivo visualmente en grandes bloques de código.




Hay una opción ternaria como se indica en otras respuestas, pero también puede simularla usando "o" si está marcando contra un valor booleano o Ninguno:

>>> a = False
>>> b = 5
>>> a or b
5

>>> a = None
>>> a or b
5



Links