Umieszczenie instrukcji if-elif-else w jednym wierszu?

125

Przeczytałem poniższe linki, ale nie dotyczą one mojego pytania.
Czy Python ma trójskładnikowy operator warunkowy? (pytanie dotyczy skondensowania instrukcji if-else do jednej linii)

Czy istnieje prostszy sposób na napisanie instrukcji if-elif-else tak, aby mieściła się w jednym wierszu?
Na przykład,

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

Lub przykład ze świata rzeczywistego:

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

Po prostu czuję, że gdyby powyższy przykład można było zapisać w następujący sposób, mógłby wyglądać na bardziej zwięzły.

x=2 if i>100 elif i<100 1 else 0 [WRONG]
Matt Elson
źródło

Odpowiedzi:

186

Nie, nie jest to możliwe (przynajmniej nie w przypadku arbitralnych stwierdzeń), ani nie jest pożądane. Umieszczenie wszystkiego w jednym wierszu najprawdopodobniej naruszyłoby PEP-8, w którym nakazuje się, aby wiersze nie przekraczały 80 znaków.

Jest to również sprzeczne z Zen Pythona: „Liczy się czytelność”. (Wpisz import thisw zachęcie Pythona, aby przeczytać całość).

W Pythonie możesz użyć wyrażenia trójskładnikowego, ale tylko dla wyrażeń, a nie dla instrukcji:

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

Edytować:

Twoje poprawione pytanie pokazuje teraz, że te trzy stwierdzenia są identyczne, z wyjątkiem przypisywanej wartości. W takim przypadku łańcuchowy operator trójskładnikowy działa, ale nadal uważam, że jest mniej czytelny:

>>> 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
źródło
Dlaczego drugie wyrażenie nie zwróciło 0? I wynosi powyżej 100
AstralWolf
6
@AstralWolf: Dziękuję bardzo! To doskonale ilustruje punkt, który próbowałem poruszyć - łańcuchowe wyrażenie trójskładnikowe jest możliwe, ale mniej czytelne i oczywiście łatwe do niezrozumienia.
Tim Pietzcker
1
Jeśli potrzebujesz, aby był bardziej czytelny, możesz umieścić go w nawiasach, w ten sposób: a = 1 if i < 100 else (2 if i > 100 else 0)(Nie przetestowano, ale myślę, że powinno działać)
Zac
@TimPietzcker jak opisałbyś różnicę między wyrażeniami a instrukcjami?
AsheKetchum
62

Jeśli potrzebujesz tylko różnych wyrażeń dla różnych przypadków, może to działać dla Ciebie:

expr1 if condition1 else expr2 if condition2 else expr

Na przykład:

a = "neg" if b<0 else "pos" if b>0 else "zero"
Lycha
źródło
1
"pos"to nie stwierdzenie, że jest to wyrażenie.
Tim Pietzcker,
@TimPietzcker Dziękuję, zaktualizowałem post, aby był bardziej dokładny.
Lycha
20

Po prostu umieść kolejną klauzulę if w instrukcji else. Ale to nie sprawia, że ​​wygląda ładniej.

>>> 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
źródło
1
Dla mnie jest to o wiele bardziej czytelne niż przyjęta odpowiedź, ponieważ zachowuje strukturę i koncepcję pierwszej klauzuli; tylko subiektywna sprawa.
Ezarate11
12

Pomimo kilku innych odpowiedzi: TAK, jest to możliwe :

if expression1:
   statement1
elif expression2:
   statement2
else:
   statement3

przekłada się na następującą jedną linijkę:

statement1 if expression1 else (statement2 if expression2 else statement3)

w rzeczywistości możesz zagnieżdżać je do nieskończoności. Cieszyć się ;)

gustavz
źródło
a co z czasem? co przypuszczam, te muti-looping będą znacznie bardziej czasochłonne. czy może więc istnieć alternatywa dla zagnieżdżonych pętli, dla lepszej szybkości konsumpcji.
loveR
cześć @loveR, to nie jest pętla, to tylko zagnieżdżona instrukcja if else, a zatem o znikomym czasie
gustavz
7

Opcjonalnie możesz faktycznie użyć getmetody dict:

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

Nie potrzebujesz tej getmetody, jeśli jeden z kluczy ma gwarantowaną wartość True:

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

Co najwyżej jeden z kluczy powinien najlepiej oceniać True. Jeśli więcej niż jeden klucz zostanie oceniony True, wyniki mogą wydawać się nieprzewidywalne.

Shane
źródło
4
if i > 100:
    x = 2
elif i < 100:
    x = 1
else:
    x = 0

Jeśli chcesz użyć powyższego kodu w jednej linii, możesz użyć:

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

W ten sposób x zostanie przypisane 2, jeśli i> 100, 1, jeśli i <100, a 0, jeśli i = 100

roshanpoudel
źródło
3

Zależy to również od charakteru twoich wypowiedzi. Ogólna rada dotycząca innych odpowiedzi „nie robić tego” jest całkiem ważna w przypadku stwierdzeń ogólnych i wyrażeń rodzajowych.

Ale jeśli wszystko, czego potrzebujesz, to tabela "wysyłkowa", na przykład wywołanie innej funkcji w zależności od wartości danej opcji, możesz umieścić funkcje do wywołania wewnątrz słownika.

Coś jak:

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

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

Zamiast if-else:

if option=="save":
    save()
...
jsbueno
źródło
2

Ludzie już wspominali o wyrażeniach trójskładnikowych. Czasami w przypadku prostego przypisania warunkowego jako przykładu można użyć wyrażenia matematycznego do wykonania przypisania warunkowego. Może to nie uczynić twojego kodu bardzo czytelnym, ale umieszcza go w jednej dość krótkiej linii. Twój przykład mógłby wyglądać następująco:

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

Porównania byłyby prawdziwe lub fałszywe, a podczas mnożenia przez liczby wyniósłby 1 lub 0. Można by użyć + zamiast | pośrodku.

Ant6n
źródło
1

Operator trójargumentowy jest najlepszym sposobem wyrażenia zwięzły. Składnia to variable = value_1 if condition else value_2. Na przykład musisz dwukrotnie zastosować operator trójskładnikowy:

i = 23 # set any value for i
x = 2 if i > 100 else 1 if i < 100 else 0
yoelvis
źródło
0

Możesz użyć zagnieżdżonych potrójnych instrukcji if.

# 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
źródło