Питання Чи має Python трійковий умовний оператор?


Якщо у Python немає термінального умовного оператора, чи можна його імітувати, використовуючи інші конструктори мови?


4442


походження


Хоча Pythons старше 2,5 повільно дрейфують до історії, ось список старих попередніх трюмів оператора від трьох: "Python Idioms", пошук за текстом "Умовний вираз" . Вікіпедія також цілком корисний :-) - ジョージ
У офіційній документації Python 3.0, зазначеній у коментарі вище, це називається "умовними виразами" і дуже криптично визначено. Ця документація навіть не включає термін "трійковий", тому вам буде важко знайти його через Google, якщо ви точно не знали, що шукати. The версія 2 документації дещо корисніше і містить посилання на "PEP 308", що включає багато цікавого історичного контексту, пов'язаного з цим питанням. - nobar
"трійковий" (має три входи) є послідовним властивістю цього impelmentation, а не визначальним властивістю концепції. наприклад: SQL має case [...] { when ... then ...} [ else ... ] end для подібного ефекту, але зовсім не трійкового. - user313114
також стандарт ISO / IEC 9899 (стандарт мови програмування С) розділ 6.5.15 називає його "оператором конфігурації" - user313114
Вікіпедія ретельно розглядає це у статті "?:". - HelloGoodbye


Відповіді:


Та це було додано у версії 2.5.
Синтаксис:

a if condition else b

Перший condition оцінюється, а потім теж a або b повертається на основі Булевський вартість condition
Якщо condition оцінює до Правда  a повертається, ще b повертається

Наприклад:

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

Зверніть увагу, що conditionals є a виразне а заява. Це означає, що ви не можете використовувати завдання або pass або інші твердження в умовному:

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

У такому випадку вам доведеться використовувати нормальний if вислів замість умовного.


Пам'ятайте, що деякі Pythonistas надихнули їх з кількох причин:

  • Порядок аргументів відрізняється від багатьох інших мов (таких як C, Ruby, Java і т. Д.), Що може призвести до помилок, коли люди, не знайомі з "дивовижною" поведінкою Python, використовують його (вони можуть змінити порядок).
  • Дехто вважає це "громіздким", оскільки воно суперечить нормі потоку думки (спочатку мислення про стан, а потім ефекти).
  • Стилістичні причини.

Якщо у вас виникають проблеми із запам'ятовуванням замовлення, пам'ятайте, що якщо ви читаєте це голосно, ви (майже) кажете, що ви маєте на увазі. Наприклад, x = 4 if b > 8 else 9 читається вголос як x will be 4 if b is greater than 8 otherwise 9.

Офіційна документація:


5299



Однак для кодерів це може здаватися дивним f(x) = |x| = x if x > 0 else -x звучить дуже природно для математиків. Ви також можете зрозуміти це, як це робить A в більшості випадків, за винятком випадків, коли C тоді ви повинні робити B замість ... - yota
Будьте обережні з порядком операцій під час використання цього. Наприклад, рядок z = 3 + x if x < y else y. Якщо x=2 і y=1, ви можете сподіватися, що виграш 4, але це дійсно досягне 1. z = 3 + (x if x > y else y) це правильне використання. - Kal Zekdor
Справа в тому, якщо ви хочете виконати додаткові оцінки після умовно оцінюється, як додавання значення результату, вам доведеться додати додатковий вираз до обох сторін (z = 3 + x if x < y else 3 + y), або групують умовні (z = 3 + (x if x < y else y) або z = (x if x < y else y) + 3) - Kal Zekdor
Пробувати @Pred print("OK" if status else "NOT OK") - BusyAnt
Я люблю невизначену іронію цього синтаксичного замовлення, що описується як природний для когось з ім'ям @yota. - nickf


Ви можете індексувати в кортеж:

(falseValue, trueValue)[test]

test потрібно повернути Правда або помилковий.
Можливо, безпечніше завжди виконувати це як:

(falseValue, trueValue)[test == True]

або ви можете використовувати вбудований bool() запевнити а Булевський значення:

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

594



Зауважте, що це завжди завжди оцінює все, тоді як construct only / else оцінює виграшне вираз. - SilverbackNet
(lambda: print("a"), lambda: print("b"))[test==true]() - Dustin Getz
Слід зазначити, що в межах []s може бути довільним виразом. Крім того, для безпеки ви можете явно перевірити правдивість, написавши [bool(<expression>)]. The bool() функція була навколо з v2.2.1. - martineau
Це чудово для коду-гольфу, а не для фактичного коду. Хоча я так звик до цього, що я іноді використовую його для лаконічності, роблячи щось очевидне, як вибір між двома константами. - Claudiu
Я зробив подібний трюк - лише раз або два, але зробив це - індексировавши в словник з True і False як ключі: {True:trueValue, False:falseValue}[test]  Я не знаю, чи є це менш ефективним, але воно, принаймні, уникає всього "елегантного" проти "потворного" дискусії. Немає сумнівів у тому, що ви маєте справу з логічним, а не з int. - JDM


Для версій до 2.5, є трюк:

[expression] and [on_true] or [on_false]

Це може дати неправильні результати, коли on_true   має помилкове логічне значення.1
Хоча це і дає перевагу оцінці виразів, що залишаються вправо, що, на мою думку, ясніше.

1 Чи існує еквівалент трійкового оператора "?:" C?


246



Засіб має використовувати (тест і [true_value] або [false_value]) [0], що дозволяє уникнути цієї лову. - ThomasH
Тернарний оператор зазвичай виконує швидше (іноді на 10-25%). - volcano
@ volcano Чи є у вас джерело для мене? - OrangeTux
@OrangeTux Ось розібраний код. Використання методу, запропонованого ThomasH, було б навіть повільніше. - mbomb007


вираз1 якщо умова інакше вираз2

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

157



Яка різниця між цією та найвищою відповіддю? - kennytm
Це підкреслює первинне наміри трійкового оператора: вибір значення. Це також показує, що більш ніж один трійковий може бути об'єднаний в одне вираження. - Roy Tinker
@ Крайг, я згоден, але також корисно знати, що станеться, коли немає дужок. У реальному коді я також схильний вставляти явні паренси. - Jon Coombs
Як-небудь я можу зрозуміти це краще, ніж найпопулярніша відповідь. - abhi divekar


Від документація:

Умовні вирази (іноді називаються "трійковим оператором") мають найменший пріоритет для всіх операцій Python.

Вираз x if C else y спочатку оцінює стан, С (не х); якщо С правда, х оцінюється і повертається його вартість; інакше у оцінюється і повертається його значення.

Побачити PEP 308 для отримання додаткової інформації про умовні вирази.

Нові з версії 2.5.


106





Оператор для умовного виразу в Python був доданий в 2006 році як частина Пропозиція щодо посилення Python 308. Його форма відрізняється від загальної ?: оператор і це:

<expression1> if <condition> else <expression2>

що еквівалентно:

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

Ось приклад:

result = x if a > b else y

Інший синтаксис, який може бути використаний (сумісний з версіями до версії 2.5):

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

де є операнди ліниво оцінював.

Інший спосіб полягає в індексації кортежу (який не відповідає умовному оператору більшості інших мов):

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

або явно сконструйований словник:

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

Інший (менш надійний), але простіший спосіб - використання and і or оператори:

result = (a > b) and x or y

однак це не буде працювати, якщо x був би False.

Можливий обхідний шлях x і y списки або кортежі, як в наступному:

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

або:

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

Якщо ви працюєте зі словниками, замість того, щоб використовувати умовно-трійковий, ви можете скористатися перевагами get(key, default), наприклад:

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

Джерело: ?: в Python у Вікіпедії


79





@up:

На жаль,

(falseValue, trueValue)[test]

рішення не має поведінки короткого замикання; таким чином, обидва значення falseValue та trueValue оцінюються незалежно від стану. Це може бути недоретимальним або навіть помилковим (тобто як trueValue, так і falseValue можуть бути методами та побічними ефектами).

Одне рішення для цього буде

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

(виконання затримується до тих пір, поки переможець не відомий;)), але це вказує на невідповідність між об'єктами, які можна викликати та не можна викликати. Крім того, це не вирішує справу при використанні властивостей.

І ось історія йде - вибір між 3 згаданих рішень - це компроміс між функцією короткого замикання, використовуючи щонайменше python 2.5 (IMHO не є проблемою більше) і не схильний до "trueValue-evaluates-to-false" помилки


72





Для Python 2.5 і новіших є певний синтаксис:

[on_true] if [cond] else [on_false]

У старших пітонах троянський оператор не реалізовано, але його можна імітувати.

cond and on_true or on_false

Хоча існує потенційна проблема, яка, якщо cond оцінює до True і on_true оцінює до False потім on_false повертається замість on_true. Якщо ви хочете цю поведінку, метод OK, інакше скористайтеся цим:

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

які можуть бути загорнуті:

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

і використовувався таким чином:

q(cond, on_true, on_false)

Він сумісний з усіма версіями Python.


48



Поведінка не ідентична - q("blob", on_true, on_false) повертає on_false, тоді як on_true if cond else on_false повертає on_true. Обхід має замінити cond з cond is not None в цих випадках, хоча це і не є ідеальним рішенням.
Чому ні bool(cond) замість cond is True? Перша перевіряє правдивість Росії cond, останній перевіряє на покажчик-рівність з True об'єкт Як підкреслював @ AndrewCecil, "blob" це правда, але це is not True. - Jonas Kölker
Вау, це виглядає дійсно згубно! :) Технічно можна навіть писати [on_false, on_True][cond is True] тому вираз стає коротшим. - Arseny


Тернарний оператор в різних програмувальних мовах

Ось я просто намагаюся показати якусь важливу різницю ternary operator між парою мов програмування.

Тернарний оператор в Javascript

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

Тернарний оператор в Рубі

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

Тернарний оператор в Scala

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

Тернарний оператор в програмуванні R

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

Тернарний оператор в Python

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

Тепер ви можете побачити красу пітонської мови. його високочитаний і ремонтопридатний.


39



Це Блоггер виявив, що троянський оператор python буде необов'язково відрізнятися від більшості інших мов. - JamesThomasMoon1979
Ruby працює також з a = true ? 1 : 0 - rneves
"Тепер ви можете побачити красу пітонської мови, її високочитає і підтримує". Я не бачу релевантності цього речення, а також того, як демонструє трійковий синтаксис оператора. - DaveMongoose
Може звучати цілеспрямовано; але те, що він по суті говорить, полягає в тому, що синтаксис Python, імовірно, буде зрозумілий людині, яка ніколи не бачив трійкового оператора, тоді як дуже мало людей зрозуміють більш звичайний синтаксис, якщо перше не сказано, що це означає. - fralau
Algol68: a = .if. .правда .потім. 1 ел. 0 .фі. Це може бути виражено також a = (. True. | 1 | 0) Як завжди, Algol68 є поліпшенням над його наступниками. - Albert van der Horst


Ви часто можете знайти

cond and on_true or on_false

але це призводить до проблеми, коли on_true == 0

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

де ви очікуєте від цього нормального трійкового оператора

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

31