Использование try vs if в python

python

49921 просмотра

9 ответа

Есть ли обоснование, чтобы решить, какой из tryили ifконструкции использовать при тестировании переменной, чтобы иметь значение?

Например, есть функция, которая возвращает список или не возвращает значение. Я хочу проверить результат перед его обработкой. Что из следующего будет более предпочтительным и почему?

result = function();
if (result):
    for r in result:
        #process items

или же

result = function();
try:
    for r in result:
        #process items
except TypeError:
    pass;

Связанное обсуждение:

Проверка существования члена в Python

Автор: artdanil Источник Размещён: 12.11.2019 09:07

Ответы (9)


204 плюса

Решение

Вы часто слышите, что Python поддерживает стиль EAFP («проще просить прощения, чем разрешения») над стилем LBYL («смотри, прежде чем прыгнуть»). Для меня это вопрос эффективности и читабельности.

В вашем примере (скажем, что вместо того, чтобы возвращать список или пустую строку, функция должна была возвращать список или None), если вы ожидаете, что 99% времени resultбудет содержать что-то итеративное, я бы использовал try/exceptподход. Это будет быстрее, если исключения действительно являются исключительными. Если resultэто Noneболее 50% времени, то, ifвероятно, лучше использовать.

Чтобы поддержать это с помощью нескольких измерений:

>>> import timeit
>>> timeit.timeit(setup="a=1;b=1", stmt="a/b") # no error checking
0.06379691968322732
>>> timeit.timeit(setup="a=1;b=1", stmt="try:\n a/b\nexcept ZeroDivisionError:\n pass")
0.0829463709378615
>>> timeit.timeit(setup="a=1;b=0", stmt="try:\n a/b\nexcept ZeroDivisionError:\n pass")
0.5070195056614466
>>> timeit.timeit(setup="a=1;b=1", stmt="if b!=0:\n a/b")
0.11940114974277094
>>> timeit.timeit(setup="a=1;b=0", stmt="if b!=0:\n a/b")
0.051202772912802175

Таким образом, в то время как ifутверждение всегда стоит вас, установить try/exceptблок практически бесплатно . Но когда это Exceptionдействительно происходит, стоимость намного выше.

Мораль:

  • Это нормально (и "питоническое") использовать try/exceptдля управления потоком,
  • но это имеет смысл больше всего, когда Exceptions на самом деле исключительны.

Из документов Python:

ЭСПЦ

Проще просить прощения, чем разрешения. Этот общий стиль кодирования Python предполагает наличие допустимых ключей или атрибутов и перехватывает исключения, если предположение оказывается ложным. Это чистый и быстрый стиль характеризуется наличием многих tryи exceptзаявлений. Техника контрастирует со стилем LBYL, общим для многих других языков, таких как C.

Автор: Tim Pietzcker Размещён: 02.12.2009 09:10

13 плюса

Ваша функция не должна возвращать смешанные типы (то есть список или пустую строку). Он должен возвращать список значений или просто пустой список. Тогда вам не нужно будет ничего проверять, то есть ваш код сворачивается в:

for r in function():
    # process items
Автор: Brandon Размещён: 02.12.2009 09:11

10 плюса

Пожалуйста, игнорируйте мое решение, если код, который я предоставляю, на первый взгляд неочевиден, и вы должны прочитать объяснение после примера кода.

Могу ли я предположить, что «значение не возвращено» означает, что возвращаемое значение равно None? Если да, или если «no value» - False в логическом смысле, вы можете сделать следующее, так как ваш код по существу обрабатывает «no value» как «not iterate»:

for r in function() or ():
    # process items

Если function()возвращает что-то, что не соответствует действительности, вы перебираете пустой кортеж, то есть вы не запускаете никаких итераций. Это по сути LBYL.

Автор: tzot Размещён: 02.12.2009 09:57

5 плюса

Ваш второй пример не работает - код никогда не сгенерирует исключение TypeError, поскольку вы можете перебирать как строки, так и списки. Итерация по пустой строке или списку также допустима - она ​​выполнит тело цикла ноль раз.

Автор: Dave Kirby Размещён: 02.12.2009 09:07

4 плюса

Что из следующего будет более предпочтительным и почему?

Смотри, прежде чем прыгать предпочтительнее в этом случае. При исключительном подходе ошибка TypeError может возникнуть в любом месте тела цикла, и она может быть захвачена и выброшена, а это не то, что вам нужно, и затруднит отладку.

(Однако я согласен с Брэндоном Корфманом: возвращение None для 'no items' вместо пустого списка не работает. Это неприятная привычка Java-кодеров, которую не следует видеть в Python. Или Java.)

Автор: bobince Размещён: 02.12.2009 10:39

4 плюса

Как правило, у меня сложилось впечатление, что исключения должны быть зарезервированы для исключительных обстоятельств. Если resultожидается, что он никогда не будет пустым (но может быть, например, в случае сбоя диска и т. Д.), Второй подход имеет смысл. Если, с другой стороны, пустое resultявляется вполне разумным в нормальных условиях, проверка на это с помощью ifутверждения имеет больше смысла.

Я имел в виду (более распространенный) сценарий:

# keep access counts for different files
file_counts={}
...
# got a filename somehow
if filename not in file_counts:
    file_counts[filename]=0
file_counts[filename]+=1

вместо эквивалента:

...
try:
    file_counts[filename]+=1
except KeyError:
    file_counts[filename]=1
Автор: Managu Размещён: 02.12.2009 09:09

3 плюса

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

result = function();
try:
    it = iter(result)
except TypeError:
    pass
else:
    for r in it:
        #process items

Как видите, это довольно некрасиво. Я не предлагаю это, но это должно быть упомянуто для полноты.

Автор: AFoglia Размещён: 03.12.2009 06:21

1 плюс

Что касается производительности, то использование блока try для кода, который обычно не вызывает исключений, быстрее, чем использование оператора if каждый раз. Итак, решение зависит от вероятности исключительных случаев.

Автор: grayger Размещён: 03.12.2009 02:33

-5 плюса

Как общее практическое правило, вы никогда не должны использовать try / catch или другие средства обработки исключений для управления потоком. Несмотря на то, что закулисная итерация контролируется с помощью возбуждения StopIterationисключений, вы все равно должны предпочесть свой первый фрагмент кода второму.

Автор: ilowe Размещён: 02.12.2009 09:12
Вопросы из категории :
32x32