¿Poner una declaración if-elif-else en una línea?

124

He leído los enlaces a continuación, pero no responde a mi pregunta.
¿Python tiene un operador condicional ternario? (la pregunta es sobre la condensación de la declaración if-else en una línea)

¿Existe una forma más fácil de escribir una declaración if-elif-else para que quepa en una línea?
Por ejemplo,

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

O un ejemplo del mundo real:

if i > 100:
    x = 2
elif i < 100:
    x = 1
else:
    x = 0

Solo siento que si el ejemplo anterior se pudiera escribir de la siguiente manera, podría parecer más conciso.

x=2 if i>100 elif i<100 1 else 0 [WRONG]
Matt Elson
fuente

Respuestas:

184

No, no es posible (al menos no con declaraciones arbitrarias), ni es deseable. Encajar todo en una línea probablemente violaría la PEP-8, donde se exige que las líneas no excedan los 80 caracteres de longitud.

También va en contra del Zen de Python: "La legibilidad cuenta". (Escriba import thisen el indicador de Python para leer todo).

Usted puede usar una expresión ternaria en Python, pero sólo para las expresiones, no por afirmaciones:

>>> a = "Hello" if foo() else "Goodbye"

Editar:

Su pregunta revisada ahora muestra que las tres declaraciones son idénticas excepto por el valor asignado. En ese caso, un operador ternario encadenado funciona, pero sigo pensando que es menos legible:

>>> i=100
>>> a = 1 if i<100 else 2 if i>100 else 0
>>> a
0
>>> i=101
>>> a = 1 if i<100 else 2 if i>100 else 0
>>> a
2
>>> i=99
>>> a = 1 if i<100 else 2 if i>100 else 0
>>> a
1
Tim Pietzcker
fuente
¿Por qué la segunda expresión no devolvió 0? i es superior a 100
astralwolf
6
@AstralWolf: ¡Muchas gracias! Esto ilustra perfectamente el punto que estaba tratando de hacer: una expresión ternaria encadenada es posible pero menos legible y obviamente fácil de malinterpretar.
Tim Pietzcker
1
Si necesita que sea más legible, puede ponerlo entre corchetes, así: a = 1 if i < 100 else (2 if i > 100 else 0)(No probado, pero creo que debería funcionar)
Zac
@TimPietzcker ¿cómo describiría la diferencia entre expresiones y declaraciones?
AsheKetchum
62

Si solo necesita diferentes expresiones para diferentes casos, esto puede funcionar para usted:

expr1 if condition1 else expr2 if condition2 else expr

Por ejemplo:

a = "neg" if b<0 else "pos" if b>0 else "zero"
Lycha
fuente
1
"pos"no es una declaración, es una expresión.
Tim Pietzcker
@TimPietzcker Gracias, actualicé la publicación para que sea más precisa.
Lycha
20

Simplemente anide otra cláusula if en la instrucción else. Pero eso no hace que se vea más bonito.

>>> x=5
>>> x if x>0 else ("zero" if x==0 else "invalid value")
5
>>> x = 0
>>> x if x>0 else ("zero" if x==0 else "invalid value")
'zero'
>>> x = -1
>>> x if x>0 else ("zero" if x==0 else "invalid value")
'invalid value'
David Lai
fuente
1
Para mí, esto es mucho más legible que la respuesta aceptada porque mantiene la estructura y el concepto de la primera cláusula; solo asunto subjetivo.
Ezarate11
12

A pesar de algunas otras respuestas: SÍ, ES posible :

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

se traduce en la siguiente línea:

statement1 if expression1 else (statement2 if expression2 else statement3)

de hecho, puedes anidarlos hasta el infinito. Disfruta;)

gustavz
fuente
¿Qué tal el tiempo necesario? lo que supongo, estos bucles mutuos consumirán mucho más tiempo. por lo que puede haber una alternativa a los bucles anidados, para una mejor velocidad de consumo.
loveR
hola @loveR, esto no es un bucle, es solo una declaración if else anidada, y por lo tanto de un tiempo insignificante
gustavz
7

Opcionalmente, puede usar el getmétodo de a dict:

x = {i<100: -1, -10<=i<=10: 0, i>100: 1}.get(True, 2)

No necesita el getmétodo si se garantiza que una de las claves se evaluará para True:

x = {i<0: -1, i==0: 0, i>0: 1}[True]

Como máximo, una de las claves idealmente debería evaluarse como True. Si se evalúa más de una clave True, los resultados pueden parecer impredecibles.

Shane
fuente
4
if i > 100:
    x = 2
elif i < 100:
    x = 1
else:
    x = 0

Si desea utilizar el código mencionado anteriormente en una línea, puede utilizar lo siguiente:

x = 2 if i > 100 else 1 if i < 100 else 0

Al hacerlo, a x se le asignará 2 si i> 100, 1 si i <100 y 0 si i = 100

roshanpoudel
fuente
3

También depende de la naturaleza de sus expresiones. El consejo general sobre las otras respuestas de "no hacerlo" es bastante válido para declaraciones genéricas y expresiones genéricas.

Pero si todo lo que necesita es una tabla de "despacho", como llamar a una función diferente dependiendo del valor de una opción dada, puede poner las funciones para llamar dentro de un diccionario.

Algo como:

def save(): 
   ...
def edit():
   ...
options = {"save": save, "edit": edit, "remove": lambda : "Not Implemented"}

option = get_input()
result = options[option]()

En lugar de un if-else:

if option=="save":
    save()
...
jsbueno
fuente
2

La gente ya ha mencionado expresiones ternarias. A veces, con una asignación condicional simple como ejemplo, es posible utilizar una expresión matemática para realizar la asignación condicional. Es posible que esto no haga que su código sea muy legible, pero lo tiene en una línea bastante corta. Su ejemplo podría escribirse así:

x = 2*(i>100) | 1*(i<100)

Las comparaciones serían Verdadero o Falso, y al multiplicar con números serían 1 o 0. Se podría usar un + en lugar de un | en el medio.

Antón
fuente
1

El operador ternario es la mejor manera de obtener una expresión concisa. La sintaxis es variable = value_1 if condition else value_2. Entonces, para su ejemplo, debe aplicar el operador ternario dos veces:

i = 23 # set any value for i
x = 2 if i > 100 else 1 if i < 100 else 0
yoelvis
fuente
0

Puede utilizar declaraciones if ternarias anidadas.

# if-else ternary construct
country_code = 'USA'
is_USA = True if country_code == 'USA' else False
print('is_USA:', is_USA)

# if-elif-else ternary construct
# Create function to avoid repeating code.
def get_age_category_name(age):
    age_category_name = 'Young' if age <= 40 else ('Middle Aged' if age > 40 and age <= 65 else 'Senior')
    return age_category_name

print(get_age_category_name(25))
print(get_age_category_name(50))
print(get_age_category_name(75))
k0L1081
fuente