2012-04-15 2 views
0

я должен иметь с версией Python < 2,5 (это 2.4.3 конкретики)Лучший способ сделать тройные условными в Python <2,5

Кажется, что тройные операторы были в Python вводит начиная с 2.5. Для тех, кто не знаком, тройные операторы в Python> = 2,5 выглядеть следующим образом:

def do_ternary(flag): 
    return "foo" if flag else "bar" 

Я хотел бы знать, какие-то решения, чтобы эмулировать в ранних версиях Python. Я могу с уверенностью это сделать, если ... еще, но я ищу что-то более питоническое, чтобы мне не стыдно было надеть какой-то код уровня производства :)

Спасибо за помощь!

+0

ваше возражение, если флаг: return "foo" else: return "bar", что он недостаточно стильный? или есть какая-то конкретная причина? – mfrankli

+0

хорошо, логика в порядке, но это не тройной оператор. На самом деле это не вопрос «стильный» или нет, это скорее о факторизации кода и написании чистого кода. Мне не очень нравится иметь целые деревья, если ... else в моем коде. –

+2

Если вы хотите что-то сделать, если тест истинен и что-то еще в противном случае, '' if ...: ... else: ... '' кажется довольно разумным. Не путайте _terse_ и _readable_. Читаемые всегда должны побеждать, если вы не можете обойти оба. –

ответ

4

На самом деле я искал в Интернете и нашел то, что кажется очень элегантным вещим решением:

def _if(test): 
    return lambda alternative: \ 
       lambda result: \ 
        [delay(result), delay(alternative)][not not test]() 

def delay(f): 
    if callable(f): return f 
    else: return lambda: f 

>>> fact = lambda n: _if (n <= 1) (1) (lambda: n * fact(n-1)) 
>>> fact(100) 
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000L 

Что вы думаете об этом? По моему мнению, он выглядит довольно чистым и легким.

+0

Я думаю, что это довольно f *** ing cool :) Я должен сказать, хотя, насколько читаемость идет, если ... тогда утверждения довольно просты. –

+1

Да, я согласен, что если ... еще самые читаемые, но я просто пытаюсь быть творческим и иметь однострочный трюк. До сих пор я считаю, что этот и @ TokenMacGuy - это те, м рассмотрение самый. –

+0

Я думаю, что это возможно наименее читаемый код, который я видел для этого. Хотя это классный код, я действительно не чувствую, что он действительно приносит пользу читателю или писателю. –

1

Классический 'трюк' используется, чтобы сделать это:

test and true_value or false_value 

Это работает как and и or работа, как это в Python:

x or y -> if x is false, then y, else x 
x and y -> if x is false, then x, else y 

Source

Это означает, что мы получить примерно такой же результат - пока true_value оценивает True - так, например, мычали бы не работы:

flag and [] or "bar" 

Как [] оценивает в False.

Я все же утверждаю, что это менее читаемо, чем просто использовать блок if/else, так как, если вы не знакомы с ним, это неясно.

Так что я бы посоветовал использовать:

if test: 
    return true_value 
else: 
    return false_value 

(замена возвращение с назначением или независимо от того, где это необходимо).

+5

Обратите внимание, что это не будет работать, как ожидалось, если 'true_value' - это то, что оценивается как' False', например. в 'flag и [] или" bar "'. – Dougal

+0

@ Дугал +1. Я добавлю эту записку - мне она никогда не нравилась сама и никогда не использовала ее, забыла об этой проблеме. –

4

Общая Хитрость заключается в том, чтобы использовать список индексацию, так как False/True превращаются в 0/1, когда требуется целое. В случае, если тест может быть ложно-у или правда-у, а не логическое, это хорошая практика, чтобы обеспечить первое испытание является булевой:

["bar", "foo"][bool(flag)] 

будет производить тот же результат, что и троичного в вашем вопросе.

Редактировать: Дугал указывает, что это может вести себя несколько иначе, чем троичный, поскольку будут оцениваться как истинные, так и ложные значения, которые могут иметь побочные эффекты.

+0

Это хорошая альтернатива, но я чувствую, что ее немного не хватает в плане удобочитаемости. Одно из преимуществ тройных операций состоит в том, что его просто читать, и, хотя это прекрасно работает, я нахожу, что он также дополняет код. –

+0

Это также не оценка короткого замыкания. – Dougal

+0

@ Дугал Это хорошая мысль. –

7

правильно путь, который делает все то, что if/else делает это:

(condition and (yes_value,) or (no_value,))[0] 

, который делает как короткое замыкание, и решает проблему, когда yes_value сама falsey.Очевидно, если у вас есть причина, чтобы избежать этой группы, просто сделайте это; в вашем примере, оба условия являются постоянными выражениями, так что вы можете сделать:

{True: yes_value, False: no_value}[bool(condition)] 

или более сжато:

(no_value, yes_value)[condition] 

если вы сделать нужен короткий circut, но вы уверены в том, что yes_value никогда не falsey, вы можете отсечь кортеж:

condition and yes_value or no_value 

, но это, вероятно, только справедливо, когда yes_value на самом деле является постоянным. Если ни один из них не удовлетворить ваши вкусы и потребности, просто использовать обычное-ол if: заявления, с промежуточным переменной

if condition: 
    result = yes_value 
else: 
    result = no_value