Python má poměrně zajímavou learning curve. Vzpomínám si, že když jsem poprvé viděl jejich návrh ternárního operátoru, tak jsem se zděsil. Teď po pár letech jsem to konečně poprvé použil, a zjistil, jsem, že to vlastně funguje perfektně, a přesně tak, jak to popisovali:
result = numerator/denominator if denominator else 0
Nelíbí se vám to co? Ale ono to funguje, a funguje to překvapivě dobře. Odpovídá to takové té sémantice, že si řekneme: asi to vyjde. Takže
result = numerator/denominator
Ale co když to nevyjde? Tak ještě přidáme podmínku.
result = numerator/denominator if denominator # syntax error
Jenže tohle nestačí, protože podle Pythonu, Explicit is better than implicit. Takže dostaneme:
result = numerator/denominator if denominator else 0
V této souvislosti bývá zmiňováno, že nějak taky funguje
result = denominator and numerator/denominator or 0
ale má to jeden háček.
n = 10 d = 5 print d and n/d or None # ==> 2 n = 0 d = 5 print d and n/d or None # ==> None ale chceme 0
Zkuste si ještě:
print 0 and [] print [] and 0 print 0 and [] or None print [] and 0 or None print None or [] and 0 print None or 0 and None
Ternární operátor strašně dlouho v pythonu nebyl, Guido ho neměl rád, proto ho do pythonu nedal. Použití and/or byl workaround chybějícího ternárního operátoru. A né moc dokolaný workaround. A podle PEP-308 jej tam dali právě kvůli tomu, že lidi používali na chyby náchylné and/or.
Pro lidi odkojené na C-like jazycích je ta syntaxe divná, ale rozumný člověk s tím nemá problém (chápu, že pro někoho je zase zápis s ?: divný).
[3] To je ternární operátor. Tedy porovná podmínku a vrátí buď A nebo B. Nejdříve verze z C:
A ? B : C // znamená pokud je splněno A, pak vrať B, jinak vrať C
Python:
B if A else C // vrať B, pokud je splněno A, jinak vrať C
Jako A samozřejmě můžete ozávorkovat cokoliv, včetně =
Ternární operátor je v céčkovské podobě hrozný přežitek. Zaplať pánbůh za jazyky, u kterých if-else-blok vrací sám o sobě hodnotu a tudíž není žádný extra ternární operátor potřeba. :)
Příklad ve Scale:
val n = 10.0
val d = 0.0
val q = if (d != 0) n / d else Double.PositiveInfinity
Ještě oprava: ono dělení nulou je na demonstraci ternárních operátorů zrovna docela blbý příklad, protože člověk musí uvažovat, co vlastně vrátit za hodnotu v kterém krajním případě, takže sémanticky správě by to bylo poněkud složitější:
def div(n: Double, d: Double) = (n, d) match {
case (0, 0) => Double.NaN
case (x, 0) if x > 0 => Double.PositiveInfinity
case (x, 0) if x Double.NegativeInfinity
case _ => n / d
}
Ale to už jsme trochu někde jinde, že jo. :)
Vůbec nechápu, to tu řešíte. Dle popisu je ternární operátor Pythonu jen čuráčtěji zapsaný ternární operátor z C, jinak je to úplně to samé. Nehledě na špínu typu „denominator“ místo „denominator = 0“, neboli implicitní záměnu typu/třídy číslo za boolean. Jestli je takovýhle celý Python, tak potěš koště. Při letmém pohledu mi vůbec přišlo, že pan Rossum vynalezl hranaté kolo.
[5] To nedává smysl!
[2] Nejlepší příspěvek.
[7] To spíš ternární operátor v C je nepovedený, přičemž se mohlo inspirovat Lispem:
(setq result (if (zerop denominator) 0 (/ numerator denominator)))
Místo pro většinu ostatních jazyků standardního užití ifu:
(if (zerop denominator) (setq result 0) (setq result (/ numerator denominator)))
Ono s "if" je to trochu problematické. On to vlastně je ternární operátor. Akorát že v C-like jazycích byl definován jako příkaz, nikoliv operátor. Ve scriptovacích jazycích ale poměrně často je implementován jako operátor a tak potřeba dalšího ternárního operátoru odpadá. Navíc mi to s ifem přijde čitelnější:
text = (if(hour12) then "PM" else "AM")
Jinak podobně úžasný je "switch" fungující jako operátor.
[8] Co nedává smysl?
„Ternární operátor je v céčkovské podobě hrozný přežitek.“ Kvůli čemu??? Prostě je klasicky céčkově úsporně zapsán pomocí speciálních znaků, zvolené pořadí podvýrazů je nepodstatné.
„Zaplať pánbůh za jazyky, u kterých if-else-blok vrací sám o sobě hodnotu a tudíž není žádný extra ternární operátor potřeba.“ A to vypadá jako jak??? Měl jste na mysli „if (d != 0) n / d else Double.PositiveInfinity“? To je ternární operátor jako každý jiný, pouze neobsahuje jeden oddělovač, jehož poloha se odvozuje z kontextu (což je taky úžasná onanie, bravo).
Ternární operátor nejde zjednodušit, protože z podstaty vyžaduje 3 výrazy. Jde ho jen různě zapsat. Takže se tu soutěží jen o to, který je prasáčtěji zapsaný.
[12] Céčkovské ?: je přežitek z toho důvodu, že v jazycích (typicky funkcionálních) je if-else blok výrazem a ne příkazem, čili sám o sobě vrací hodnotu. Z toho důvodu není potřeba mít extra jazykový konstrukt pro ternární operátor, protože v takovémhle jazyce není mezi ternárním operátorem a klasickou podmínkou žádný rozdíl, je to jedno a to samé (což zmiňovali i [9] a [10]).
Takže místo:
RESULT = CONDITION ? A : B
prostě napíšu:
RESULT = if (CONDITION) A else B
Stejně tak existuje i varianta switch bloku, která taky sama o sobě vrací výraz, viz [6] (redakční systém mi tam odstranil ze 4. řádky pár znaků, ale to je detail).
Aha! Tak to jste měl rovnou napsat, že je to výraz (pochopitelně z ternárního operátoru) místo příkazu (imperativu). To ale pak není věcí redundance, ale srovnání funkcionálního jazyku s imperativním, kdy funkcionální jazyk imperativní konstrukce pochopitelně nemá (bez ohledu na syntaxi zápisu výrazů).
Ten příklad kulhá na jednu nohu. Uvědom si, že kdybys tohle napsal ve velkém programu, tak chybu dělení nulou nikdy neodhalíš a bude to někde na druhém konci dávat velmi zlé výsledky. Tady je jednoznačně nejlepší vyhodit výjimku. Pak to celé nějak ošetřit, aby s tím obsluha mohla něco dělat.
Jmenuju se Petr Blahoš. Programuju něco přes 20 let. Tady se snažím psát hlavně o Pythonu, webovém frameworku Pyramid, a občas i o něčem úplně jiném.
Přečteno 19 231×
Přečteno 11 855×
Přečteno 9 354×
Přečteno 8 812×
Přečteno 8 599×