Colocando uma instrução if-elif-else em uma linha?

124

Eu li os links abaixo, mas não respondem à minha dúvida.
O Python tem um operador condicional ternário? (a questão é sobre condensar a instrução if-else em uma linha)

Existe uma maneira mais fácil de escrever uma instrução if-elif-else para que ela caiba em uma linha?
Por exemplo,

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

Ou um exemplo do mundo real:

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

Eu apenas sinto que se o exemplo acima pudesse ser escrito da seguinte maneira, poderia parecer mais conciso.

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

Respostas:

184

Não, não é possível (pelo menos não com declarações arbitrárias), nem é desejável. Ajustar tudo em uma linha provavelmente violaria o PEP-8, onde é obrigatório que as linhas não tenham mais de 80 caracteres.

Também é contra o Zen do Python: "A legibilidade conta". (Digite import thisno prompt do Python para ler tudo).

Você pode usar uma expressão ternária em Python, mas apenas para expressões, não para instruções:

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

Editar:

Sua pergunta revisada agora mostra que as três afirmações são idênticas, exceto pelo valor que está sendo atribuído. Nesse caso, um operador ternário encadeado funciona, mas ainda acho que é menos legível:

>>> 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
fonte
Por que a segunda expressão não retornou 0? estou acima de 100
AstralWolf
6
@AstralWolf: Muito obrigado! Isso ilustra perfeitamente o que eu estava tentando fazer - uma expressão ternária encadeada é possível, mas menos legível e, obviamente, fácil de interpretar mal.
Tim Pietzcker
1
Se precisar que ele seja mais legível, você pode colocar colchetes ao redor, assim: a = 1 if i < 100 else (2 if i > 100 else 0)(Não testado, mas acho que deve funcionar)
Zac
@TimPietzcker como você descreveria a diferença entre expressões e afirmações?
AsheKetchum
62

Se você só precisa de expressões diferentes para casos diferentes, isso pode funcionar para você:

expr1 if condition1 else expr2 if condition2 else expr

Por exemplo:

a = "neg" if b<0 else "pos" if b>0 else "zero"
Lycha
fonte
1
"pos"não é uma declaração, é uma expressão.
Tim Pietzcker
@TimPietzcker Obrigado, atualizei o post para ser mais preciso.
Lycha
20

Apenas aninhe outra cláusula if na instrução else. Mas isso não faz com que pareça mais 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
fonte
1
Para mim, isso é muito mais legível do que a resposta aceita porque mantém a estrutura e o conceito da primeira cláusula; apenas questão subjetiva.
Ezarate11
12

Apesar de algumas outras respostas: SIM, é possível :

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

se traduz no seguinte forro:

statement1 if expression1 else (statement2 if expression2 else statement3)

na verdade, você pode aninhá-los até o infinito. Aproveitar ;)

Gustavz
fonte
que tal o tempo gasto? o que eu suponho, esses muti-looping levarão muito mais tempo. portanto, pode haver uma alternativa para loops aninhados, para melhor velocidade de consumo.
loveR
oi @loveR, isso não é um loop, é apenas uma instrução if else aninhada e, portanto, de tempo insignificante
gustavz
7

Você pode, opcionalmente, usar o getmétodo de dict:

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

Você não precisa do getmétodo se uma das chaves for avaliada como True:

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

Idealmente, no máximo uma das chaves deve ser avaliada como True. Se mais de uma chave for avaliada como True, os resultados podem parecer imprevisíveis.

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

Se quiser usar o código mencionado acima em uma linha, você pode usar o seguinte:

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

Ao fazer isso, x será atribuído 2 se i> 100, 1 se i <100 e 0 se i = 100

Roshanpoudel
fonte
3

Também depende da natureza de suas expressões. O conselho geral sobre as outras respostas de "não fazer isso" é bastante válido para declarações e expressões genéricas.

Mas se tudo que você precisa é uma tabela de "despacho", como chamar uma função diferente dependendo do valor de uma determinada opção, você pode colocar as funções a serem chamadas dentro de um dicionário.

Algo como:

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

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

Em vez de um if-else:

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

As pessoas já mencionaram expressões ternárias. Às vezes, com uma atribuição condicional simples como exemplo, é possível usar uma expressão matemática para realizar a atribuição condicional. Isso pode não tornar o seu código muito legível, mas o coloca em uma linha bastante curta. Seu exemplo poderia ser escrito assim:

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

As comparações seriam verdadeiras ou falsas e, ao multiplicar por números, seria 1 ou 0. Pode-se usar um + em vez de um | no meio.

Ant6n
fonte
1

O operador ternário é a melhor maneira de uma expressão concisa. A sintaxe é variable = value_1 if condition else value_2. Portanto, para seu exemplo, você deve aplicar o operador ternário duas vezes:

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

Você pode usar instruções if ternárias aninhadas.

# 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
fonte