Python: как избежать условия if?

Что лучше?

if not var:
    var = get_var()
(или)

var = var или get_var ()

Кроме того, как мне узнать лучшее из двух?
edit:
Еще один вариант от Стива,

var = var if var else get_var()

person asdfg    schedule 11.03.2010    source источник
comment
Также учтите: var = var if var else getvar () - в данном случае не обязательно рекомендация, это просто еще один вариант.   -  person Steve314    schedule 11.03.2010
comment
Что, если get_var () вернет 0? Вы будете продолжать называть его, даже если вам уже известна его стоимость.   -  person PaulMcG    schedule 11.03.2010
comment
это должно было быть get_new_var () ..   -  person asdfg    schedule 11.03.2010
comment
Это вообще не позволяет избежать условия if. Что ты спрашиваешь?   -  person S.Lott    schedule 11.03.2010
comment
Если вам нужна новая переменная каждый раз, почему бы вам просто не написать var = get_new_var()?   -  person PaulMcG    schedule 12.03.2010


Ответы (9)


Лучше тот, который тебе больше нравится. Я бы использовал первую версию с if, но это очень личное.

person Michał Niklas    schedule 11.03.2010

Когда два варианта стилей настолько близки стилистически, я использую timeit в качестве решающего фактора: быстрее должно означать ближе к основному потоку Python, то есть лучше. Эй, это лучше, чем бесконечные споры, а? -) Итак:

$ python -mtimeit -s'var=0; getvar=lambda:0' 'var = var or getvar()'
1000000 loops, best of 3: 0.359 usec per loop
$ python -mtimeit -s'var=0; getvar=lambda:0' 'if not var: var = getvar()'
1000000 loops, best of 3: 0.361 usec per loop
$ python -mtimeit -s'var=1; getvar=lambda:1' 'var = var or getvar()'
10000000 loops, best of 3: 0.123 usec per loop
$ python -mtimeit -s'var=1; getvar=lambda:1' 'if not var: var = getvar()'
10000000 loops, best of 3: 0.0899 usec per loop

у if это есть - эквивалентно, когда var ложно, быстрее, когда true.

person Alex Martelli    schedule 11.03.2010
comment
Когда все остальное не имеет значения, оптимизируйте работу на микроуровне! - person Chris Lutz; 11.03.2010
comment
@Chris, я вижу это скорее как выяснение того, что является основным направлением Python - разработчики ядра Python (включая меня) в конечном итоге тратят намного больше времени на оптимизацию использования, которое часто и ценится, а не маргинальное и насмешливое, поэтому timeit - это способ зафиксировать общую сумму их (наших) усилий для принятия спорного решения. - person Alex Martelli; 11.03.2010
comment
кажется мне немного противоречивым, как еще они тогда реализовали короткое cicuiting? - person Johannes Rudolph; 11.03.2010
comment
@Alex - Мой комментарий должен был быть более насмешливым, чем он читается. Простите за мои любительские навыки интернет-сарказма. - person Chris Lutz; 11.03.2010
comment
@ Крис, конечно, просто хотел прояснить мои рассуждения. @Johannes, x=x не оптимизируется компилятором Python, который на самом деле является супер-простым компилятором, поэтому тот факт, что короткое замыкание приводит к эквиваленту var=var, не делает последний бесплатным! -) - person Alex Martelli; 11.03.2010
comment
@Chris: Я был единственным сторонником твоей шутливой остроты. Я удивлен, что этот комментарий к настоящему времени не стал известным (показывает, насколько я потерял связь с духом времени SO). Смешные отрывки что-то теряют при анализе, но, по сути, мне понравились его краткость, его [очевидный] несерьезный характер (who would imagine Alex as an advocate for micro-optimization ?) и, прежде всего, облегчение, которое он предоставил на серьезной, но тем не менее анекдотической теме. Когда дело доходит до Python, Алекс серьезно относится ко всему, по крайней мере, по умолчанию. - person mjv; 11.03.2010

На самом деле, если вы пытаетесь определить, была ли ранее установлена ​​переменная var с помощью вызова get_var, я бы сказал, что обе формы неверны. Python обрабатывает ряд совершенно обычных значений как вычисляющих логическое значение false: 0, None, [], (,), set () и {}. Итак, предположим, что var будет целым числом, а get_var () вернет 0. Теперь, независимо от того, какую форму вы используете, get_var () будет вызываться снова и снова, даже если мы уже знаем, что var равно 0!

Существует несколько методов определения того, была ли определена переменная:

  • посмотрите в слове, возвращаемом globals () или locals ()

  • заключить оператор var = var в блок try / except, захватить NameError

  • используйте контрольное значение, например None, и инициализируйте var этим значением; тогда вы можете проверить if var is None: var = get_var() (используя 'is', а не '=='). Если вам не повезло, и None - это потенциальное значение, которое может быть возвращено get_var (), вам нужно будет определить свое собственное специальное еще не определенное значение, используя что-то вроде NOT_DEFINED = object(), инициализировать var с его помощью, а затем вы можете тест на if var is NOT_DEFINED.

person PaulMcG    schedule 11.03.2010

Для меня первая идиома, использующая явное if, предпочтительнее, потому что она более явная.

Однако я видел, что конструкция or упоминается как предпочтительная / более питоническая.

Итак, с одной стороны, Explicit is better than implicit (цитирование Дзэн), с другой стороны, короткое выражение можно рассматривать как питоническое (хотя короче не во всех случаях эквивалентно питоническому!)

Тесно связанный вопрос SO - это самый идиоматический способ преобразования None в пустую строку, и там были перечислены идиомы if и or.

person mjv    schedule 11.03.2010

первая версия мне более интуитивно понятна. Но опять же, все дело в вашем собственном вкусе.

person ghostdog74    schedule 11.03.2010

Второй более питонический, и я обычно его использую.

person YOU    schedule 11.03.2010
comment
означает ли это, что конструкция if не является Pythonic? что составляет Pythonic? - person ghostdog74; 11.03.2010
comment
ИМО, это больше Pythonic , если var оказывается логическим. В противном случае, вероятно, нет, хотя контекст может изменить мое мнение. - person Steve314; 11.03.2010

Ни то, ни другое не так.

Первый вариант более понятен тем, кто читает код.

Спросите себя, когда вы думаете о проблеме, которую пытаетесь решить, идеи, которые приходят вам на ум, ближе к «если это, то то» или «логическому ИЛИ двух почти, но не совсем логических переменных».

person Oddthinking    schedule 11.03.2010

Оба в конечном итоге будут скомпилированы в один и тот же код, учитывая, что или является оператором короткого замыкания (он не оценивает аргумент правой руки, если левая сторона истинна).

Я бы предпочел первый, так как он более четко выражает ваши намерения. Второй, наверное, более компактный.

person Johannes Rudolph    schedule 11.03.2010

Интерпретатор, скорее всего, выполнит их в обоих направлениях. Есть компромиссы относительно читабельности кода. Какое утверждение легче распознать, что оно делает? Конечно, первое гораздо яснее. Мне, читая этот пост, пришлось больше думать о втором. Я бы использовал первое из-за большей читабельности, даже если второе утверждение немного «сексуальнее».

Надеюсь это поможет.
-tjw

person Travis Webb    schedule 11.03.2010