Бы быть подходящие для Python, чтобы использовать `или`, подобно тому, как в PHP использовать `или умереть()`?


Это подходящие для Python, чтобы использовать or, Подобно тому, как в PHP могла бы использовать or die()?

Я использую
quiet or print(stuff)
вместо того, чтобы
if verbose: print(stuff)
недавно.

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

or

  
  2           0 LOAD_FAST                0 (quiet)
              3 JUMP_IF_TRUE_OR_POP     15
              6 LOAD_GLOBAL              0 (print)
              9 LOAD_CONST               1 ('foo')
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
        >>   15 POP_TOP
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE

Vs if


  2           0 LOAD_FAST                0 (verbose)
              3 POP_JUMP_IF_FALSE       19

  3           6 LOAD_GLOBAL              0 (print)
              9 LOAD_CONST               1 ('bar')
             12 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             15 POP_TOP
             16 JUMP_FORWARD             0 (to 19)
        >>   19 LOAD_CONST               0 (None)
             22 RETURN_VALUE
2 7

2 ответа:

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


Правильный способ написать это очевидный способ:

if verbose:
    print(stuff)

Или, если вычисление stuff само по себе не дорого / опасно/безотзывно, просто оберните print в функцию, которая проверяет флаг:

def printv(*args, **kwargs):
    if verbose:
        print(*args, **kwargs)

... так что вы можете просто сделать это, что примерно так кратко, как вы собираетесь получить:

printv(stuff)

Или, еще лучше, использовать logging модуль вместо изобретения колеса.


Но что делать, если stuff стоит дорого, и вы действительно хотите сохранить строку?

Ну, вам, вероятно, на самом деле не нужно сохранять строку, и это всегда приносит в жертву читабельность для краткости; "читабельность считается" - ключевая частьДзен Python . Но Python позволяет поместить однострочный набор на ту же строку, что и условие:

if verbose: print(stuff)

Как говорит PEP 8 , " иногда это ладно", но это "вообще обескураживает". Как выразился Гвидо в письме из списка рассылки ideas, "Если вам нужно сохранить строку, используйте однострочный оператор if, а не что-то "умное". Но если вы должны сохранить строку, я, вероятно, не хочу читать ваш код."

Если вы хотите этого в выражении (которое вы не должны, как я объясню ниже), или вы хотите технически следовать PEP 8 до буквы, грубо нарушая дух:

print(stuff) if verbose else None

Итак, что же не так Питон об этом?

Во-первых, вы используете результат print в выражении, хотя print не имеет полезного результата и вызывается только для его побочных эффектов. Это вводит в заблуждение.

И вообще, Python имеет только один побочный эффект на строку, и это происходит как можно дальше влево, что позволяет легко просматривать код и видеть, что меняется. Это усиливается сильным разделением между высказываниями и выражениями (и, например, присваиваниями, являющимися высказываниями). методы с побочными эффектами, идиоматически возвращающие None вместо self, и так далее.

Но даже игнорирование всего этого, использование and и or только для короткого замыкания, а не для их результатов, потенциально сбивает с толку и, по крайней мере, в сознании некоторых людей, уродливо. Вот почему было добавлено тернарное выражение (spam if eggs else beans): чтобы люди перестали писать eggs and spam or beans. Почему это сбивает с толку? Во-первых, он вообще не читается как английский, если только вы не читали больше кода Perl, чем настоящий английский. Во-вторых, очень легко случайно использовать допустимое значение, которое оказывается ложным; вы знаете, что этого делать не следует, и проверить это, когда вы видите if, но здесь вы этого не делаете. Также обратите внимание, что print(stuff) if verbose else None делает явным, что вы создаете значение, с которым затем ничего не делаете; явное всегда лучше, чем неявное, но особенно когда вы делаете что-то необычное.

Наконец, что касается производительности: (а) кого это волнует, и (Б) почему бы не измерить ее вместо этого или попытаться угадать, читая байт-код, который вы не понимаете?

In [511]: quiet = True
In [512]: %timeit quiet or None
10000000 loops, best of 3: 48.2 ns per loop
In [513]: verbose=False
In [514]: %timeit if verbose: pass
10000000 loops, best of 3: 38.5 ns per loop

Итак, в случае быстрого прохождения оператор if на самом деле примерно на 20% быстрее, а не медленнее-и они оба настолько быстры, что вряд ли когда-либо повлияют на вашу программу в любом случае. Если вы делаете это миллиард раз в узком цикле и вам нужно выжать эту производительность, вы захотите вытащить остальное из цикла, даже если это означает повторение с двумя почти клонами одного и того же кода (особенно учитывая, что цикл без prints с большей вероятностью поместится в кэш и т. д.).

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

Я не думаю, что это питон. ("Явное лучше, чем неявное").

Вы можете написать

if verbose: print(stuff)

Так что если вам отчаянно нужно вести обратный отсчет, вы можете.

Наиболее подходящие для Python способ ("читабельность имеет значение.") все равно будет использовать

if verbose:
    print(stuff)