Pytanie Czy Python ma potrójny operator warunkowy?


Jeśli Python nie ma potrójnego operatora warunkowego, czy można go symulować za pomocą innych konstrukcji językowych?


4442


pochodzenie


Chociaż Pythony starsze niż 2.5 powoli dryfują do historii, tutaj znajduje się lista starych tri-operatorów operatora trój-2.5: "Idiomy Pythona", wyszukaj tekst "Wyrażenie warunkowe" . Wikipedia jest również bardzo pomocny Ж :-) - ジョージ
W oficjalnej dokumentacji Pythona 3.0, do której odwołuje się powyższy komentarz, jest to określane jako "warunkowe_wyrażenia" i jest bardzo kryptycznie zdefiniowane. Ta dokumentacja nie zawiera nawet określenia "trójkowego", więc trudno znaleźć go za pośrednictwem Google, chyba że dokładnie wiesz, czego szukać. The dokumentacja w wersji 2 jest nieco bardziej pomocny i zawiera link do "PEP 308", która zawiera wiele interesujących kontekstów historycznych związanych z tym pytaniem. - nobar
"trójskładnik" (posiadający trzy nakłady) jest następną właściwością tej impelmentacji, a nie definiującą właściwością tej koncepcji. np .: SQL ma case [...] { when ... then ...} [ else ... ] end dla podobnego efektu, ale nie dla trójskładnika. - user313114
także ISO / IEC 9899 (standard języka programowania C) sekcja 6.5.15 nazywa go "operatorem warunkowym" - user313114
Wikipedia dokładnie to opisuje w artykule "?:". - HelloGoodbye


Odpowiedzi:


Tak, było dodany w wersji 2.5.
Składnia jest następująca:

a if condition else b

Pierwszy condition jest oceniany, a następnie albo a lub b jest zwracana w oparciu o Boolean wartość condition
Gdyby condition ocenia na Prawdziwe  a jest zwracany, w przeciwnym razie b jest zwracany.

Na przykład:

>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'

Zwróć uwagę, że warunkowe są wyrażenienie a komunikat. Oznacza to, że nie możesz używać przypisań ani pass lub inne instrukcje warunkowe:

>>> pass if False else x = 3
  File "<stdin>", line 1
    pass if False else x = 3
          ^
SyntaxError: invalid syntax

W takim przypadku musisz użyć normalnego if oświadczenie zamiast warunkowego.


Należy pamiętać, że niektóre Pythonistas są niezadowolone z kilku powodów:

  • Kolejność argumentów różni się od wielu innych języków (takich jak C, Ruby, Java itd.), Co może prowadzić do błędów, gdy ludzie, którzy nie znają "zaskakującego" zachowania Pythona, używają go (mogą odwrócić kolejność).
  • Niektórzy uważają ją za "nieporęczną", ponieważ jest ona sprzeczna z normalnym przepływem myśli (najpierw myśl o stanie, a potem o skutkach).
  • Powody stylistyczne.

Jeśli masz problemy z zapamiętaniem porządku, pamiętaj, że jeśli czytasz to głośno, (prawie) mówisz, co masz na myśli. Na przykład, x = 4 if b > 8 else 9 jest czytany na głos jako x will be 4 if b is greater than 8 otherwise 9.

Oficjalne dokumenty:


5299



Jednak kolejność może wydawać się dziwna dla programistów f(x) = |x| = x if x > 0 else -x brzmi bardzo naturalnie dla matematyków. Możesz również zrozumieć to jako A w większości przypadków, z wyjątkiem sytuacji, gdy C to powinieneś zrobić B zamiast ... - yota
Zachowaj ostrożność przy kolejnosci operacji podczas korzystania z tego. Na przykład linia z = 3 + x if x < y else y. Gdyby x=2 i y=1można się spodziewać, że przyniesie 4, ale faktycznie da 1. z = 3 + (x if x > y else y) jest prawidłowe użycie. - Kal Zekdor
Chodziło o to, jeśli chcesz wykonać dodatkowe oceny po Warunek jest oceniany, podobnie jak dodanie wartości do wyniku, musisz dodać dodatkowe wyrażenie do obu stron (z = 3 + x if x < y else 3 + y) lub zgrupuj warunkowe (z = 3 + (x if x < y else y) lub z = (x if x < y else y) + 3) - Kal Zekdor
@Pred spróbuj print("OK" if status else "NOT OK") - BusyAnt
Bardzo podoba mi się niejasna ironia tego składniowego uporządkowania określanego jako naturalny przez kogoś o nazwie @yota. - nickf


Możesz indeksować do krotki:

(falseValue, trueValue)[test]

test musi wrócić Prawdziwe lub Fałszywy.
Bezpieczniejsze może być zawsze implementowanie go jako:

(falseValue, trueValue)[test == True]

lub możesz użyć wbudowanego bool() zapewnić Boolean wartość:

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

594



Zauważ, że ta zawsze ocenia wszystko, podczas gdy konstrukcja if / else ocenia tylko wygrywające wyrażenie. - SilverbackNet
(lambda: print("a"), lambda: print("b"))[test==true]() - Dustin Getz
Należy zauważyć, że to, co jest w środku []s może być dowolną ekspresją. Ponadto, dla bezpieczeństwa można wyraźnie sprawdzić prawdę, pisząc [bool(<expression>)]. The bool() funkcja istnieje już od wersji 2.2.1. - martineau
To jest świetne dla code-golfa, a nie dla prawdziwego kodu. Chociaż przyzwyczaiłem się do tego, że używam go czasami dla zwięzłości, gdy robię coś oczywistego, jak wybieranie między dwiema stałymi stałymi. - Claudiu
Zrobiłem podobną sztuczkę - tylko raz lub dwa razy, ale zrobiłem to - poprzez indeksowanie do słownika z True i False jako klucze: {True:trueValue, False:falseValue}[test]  Nie wiem, czy jest to mniej skuteczne, ale przynajmniej omija całą debatę "elegancką" i "brzydką". Nie ma dwuznaczności, że masz do czynienia z wartością boolowską, a nie int. - JDM


W wersjach sprzed wersji 2.5 istnieje pewna sztuczka:

[expression] and [on_true] or [on_false]

Może dawać złe wyniki, kiedy on_true   ma fałszywą wartość boolowską.1
Chociaż ma on zaletę oceniania wyrażeń od lewej do prawej, co moim zdaniem jest jaśniejsze.

1. Czy istnieje odpowiednik operatora potrójnego "?:" C?


246



Środkiem zaradczym jest użycie (test i [true_value] lub [false_value]) [0], co pozwala uniknąć tej pułapki. - ThomasH
Ternary operator zwykle wykonuje się szybciej (czasami o 10-25%). - volcano
@volcano Czy masz dla mnie źródło? - OrangeTux
@OrangeTux Oto zdemontowany kod. Korzystanie z metody zaproponowanej przez ThomasH byłoby jeszcze wolniejsze. - mbomb007


wyrażenie1 gdyby stan jeszcze wyrażenie2

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

157



Jaka jest różnica między tą a najwyższą odpowiedzią? - kennytm
Ta uwydatnia pierwotną intencję trójskładnikowego operatora: wybór wartości. Pokazuje również, że więcej niż jedno potrójne połączenie może być połączone w jedno wyrażenie. - Roy Tinker
@Craig, zgadzam się, ale dobrze jest wiedzieć, co się stanie, gdy nie ma nawiasów. W prawdziwym kodzie, ja też miałbym tendencję do wstawiania wyraźnych paren. - Jon Coombs
W jakiś sposób jestem w stanie to zrozumieć lepiej niż najwyższą odpowiedź. - abhi divekar


Od dokumentacja:

Wyrażenia warunkowe (czasami nazywane "operatorem potrójnym") mają najniższy priorytet wszystkich operacji w Pythonie.

Ekspresja x if C else y najpierw ocenia stan, do (nie x); gdyby do jest prawdziwy, x jest oceniany, a jego wartość jest zwracana; Inaczej, y jest obliczany i zwracana jest jego wartość.

Widzieć PEP 308 aby uzyskać więcej informacji na temat wyrażeń warunkowych.

Nowe od wersji 2.5.


106





Operator wyrażenia warunkowego w Pythonie został dodany w 2006 roku jako część Python Enhancement Proposal 308. Jego forma różni się od zwykłej ?: operator i to:

<expression1> if <condition> else <expression2>

co jest równoznaczne z:

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

Oto przykład:

result = x if a > b else y

Inna składnia, której można użyć (zgodna z wersjami przed wersją 2.5):

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

gdzie są operandy leniwie oceniany.

Innym sposobem jest indeksowanie krotki (która nie jest zgodna z operatorem warunkowym większości innych języków):

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

lub jawnie skonstruowany słownik:

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

Inną (mniej niezawodną), ale prostszą metodą jest użycie and i or operatorzy:

result = (a > b) and x or y

jednak to nie zadziała, jeśli x byłoby False.

Możliwe rozwiązanie problemu x i y listy lub krotki, jak poniżej:

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

lub:

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

Jeśli pracujesz ze słownikami, zamiast korzystać z warunkowego warunku, możesz skorzystać get(key, default), na przykład:

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

Źródło: ?: w Pythonie w Wikipedii


79





@w górę:

Niestety

(falseValue, trueValue)[test]

rozwiązanie nie ma właściwości zwarciowych; zatem zarówno falseValue, jak i trueValue są oceniane niezależnie od warunku. Może to być suboptymalne lub nawet błędne (to jest zarówno trueValue, jak i falseValue mogą być metodami i mieć efekty uboczne).

Jednym z rozwiązań byłoby to

(lambda: falseValue, lambda: trueValue)[test]()

(wykonanie opóźnione, dopóki zwycięzca nie jest znany;)), ale wprowadza niespójność pomiędzy obiektami wywoływalnymi a obiektami, których nie można wywołać. Ponadto nie rozwiązuje problemu przy korzystaniu z właściwości.

I tak historia się toczy - wybór między trzema wspomnianymi rozwiązaniami jest kompromisem między funkcją zwarcia, przy użyciu co najmniej python 2.5 (IMHO nie stanowi już problemu) i nie jest podatny na "trueValue-ocenia-to-false" błędy.


72





W Pythonie 2.5 i nowszych jest określona składnia:

[on_true] if [cond] else [on_false]

W starszych pythonach potrójny operator nie jest zaimplementowany, ale można go symulować.

cond and on_true or on_false

Chociaż istnieje potencjalny problem, który jeśli cond ocenia na True i on_true ocenia na False następnie on_false jest zwracana zamiast on_true. Jeśli chcesz tego zachowania, metoda jest OK, w przeciwnym razie użyj tego:

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

które mogą być pakowane przez:

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

i używane w ten sposób:

q(cond, on_true, on_false)

Jest kompatybilny ze wszystkimi wersjami Pythona.


48



Zachowanie nie jest identyczne - q("blob", on_true, on_false) zwraca on_false, natomiast on_true if cond else on_false zwraca on_true. Obejście to zastąpienie cond z cond is not None w takich przypadkach, chociaż nie jest to idealne rozwiązanie.
Dlaczego nie bool(cond) zamiast cond is True? Pierwszy sprawdza prawdę cond, ten drugi sprawdza, czy wskaźnik-równość z True obiekt. Jak podkreślono przez @AndrewCecil, "blob" jest prawda, ale to is not True. - Jonas Kölker
Wow, wygląda na naprawdę hacky! :) Technicznie, możesz nawet pisać [on_false, on_True][cond is True] więc wyrażenie staje się krótsze. - Arseny


Ternary Operator w różnych językach programowania

Tutaj staram się pokazać jakąś ważną różnicę ternary operator między kilkoma językami programowania.

Ternary Operator w JavaScript

var a = true ? 1 : 0;
# 1
var b = false ? 1 : 0;
# 0

Ternary Operator w Ruby

a = true ? 1 : 0
# 1
b = false ? 1 : 0
# 0

Ternary operator w Scala

val a = true ? 1 | 0
# 1
val b = false ? 1 | 0
# 0

Ternary operator w programowaniu R.

a <- if (TRUE) 1 else 0
# 1
b <- if (FALSE) 1 else 0
# 0

Ternary operator w Pythonie

a = 1 if True else 0
# 1
b = 1 if False else 0
# 0

Teraz możesz zobaczyć piękno języka Pythona. jest bardzo czytelny i łatwy w utrzymaniu.


39



To blogger stwierdził, że potrójny operator Pythona jest niepotrzebnie inny niż większość innych języków. - JamesThomasMoon1979
Ruby działa również z a = true ? 1 : 0 - rneves
"Teraz możesz zobaczyć piękno języka Pythona, które jest bardzo czytelne i łatwe w utrzymaniu". Nie widzę znaczenia tego zdania ani tego, jak demonstruje to składnia potrójnego operatora. - DaveMongoose
Może wydawać się upartym; ale zasadniczo mówi się, że składnia Pythona może być zrozumiana przez osobę, która nigdy nie widziała operatora trójskładnikowego, podczas gdy bardzo niewielu ludzi zrozumie bardziej typową składnię, o ile nie powiedziano jej najpierw, co to znaczy. - fralau
Algol68: a = .if. .prawdziwe. .następnie. 1 .else. 0 .fi. Można to wyrazić również a = (. True. | 1 | 0). Jak zwykle Algol68 stanowi ulepszenie w stosunku do jego następców. - Albert van der Horst


Często możesz znaleźć

cond and on_true or on_false

ale to prowadzi do problemu, gdy on_true == 0

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

gdzie można oczekiwać od zwykłego operatora trójskładnikowego tego wyniku

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

31