Избегать исключений?

Этот конкретный пример относится к Django в Python, но должен применяться к любому языку, поддерживающему исключения:

try:
    object = ModelClass.objects.get(search=value)
except DoesNotExist:
    pass

if object:
    # do stuff

Класс модели Django предоставляет простой метод получать, который позволяет мне искать объект один и только один в базе данных, если он находит более или менее, он вызывает исключение. Если можно найти ноль или более с помощью альтернативного метода фильтр, который возвращает список:

objects = ModelClass.objects.filter(search=value)
if len(objects) == 1:
    object = objects[0]
    # do stuff

Я слишком не люблю исключения? Мне это исключение кажется немного расточительным, предположительно, от четверти до половины времени будет «исключительным». Я бы предпочел функцию, которая возвращает Никто в случае сбоя. Могу ли я использовать метод Django фильтр и обработать список самостоятельно?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
0
2 136
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Подсказка кроется в названии - исключения должны быть исключительными.

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

Итак, учитывая, что вы указали, что от 1 из 2 до 1 из 4 не будет существовать, я бы определенно написал оболочку для filter, поскольку это определенно не исключительный случай.

Ответ будет зависеть от цели кода. (Я не уверен, что должен был делать ваш образец кода, проход в исключительном случае сбивает с толку, что будет делать остальная часть кода с переменной object для работы?)

Использовать ли исключения или использовать метод, который рассматривает случай как неисключительный, во многих случаях - дело вкуса. Конечно, если реальный код в предложении except так же сложен, как метод фильтрации, который вам придется использовать, чтобы избежать исключения, тогда используйте метод filter. Чем проще код, тем лучше.

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


Редактировать:

В ответ на запрос чисел по этому поводу я провел этот простой тест ...

import time

def timethis(func, list, num):
  st=time.time()
  for i in xrange(0,1000000):
    try:
      func(list,num)
    except:
      pass
  et = time.time()
  print "Took %gs" % (et-st)

def check(list, num):
  if num < len(list):
    return list[num]
  else:
    return None

a=[1]
timethis(check, a, 1)
timethis(lambda x,y:x[y], a, 1)

И выход был ..

Took 0.772558s
Took 3.4512s

HTH.

Можете ли вы предоставить некоторые измерения, сравнивающие версии с исключениями и без исключения? Хотелось бы посмотреть, насколько велико это "заметное" попадание на самом деле.

S.Lott 03.01.2009 22:29

Для записи, оба этих примера вызывают исключение StopIteration. ИМО это показывает, что исключения НЕ оказывают существенного влияния на производительность при разумном использовании.

Jason Baker 04.01.2009 03:24

a [1] выдаст вам IndexError. Итерация продолжается, потому что исключение перехватывается и передается в цикле. Я утверждаю, что мой пример действителен, поскольку показывает, что переданные исключения в цикле могут снизить производительность (в данном случае 5x).

Jimmy2Times 04.01.2009 03:48

Это неверно. В контексте вопроса значимой проблемы с производительностью нет. Ваш тест выполняет 1 миллион итераций, а версия с исключениями заняла 3,5 секунды. Это означает, что стоимость каждого исключения составляет примерно 0,0035 миллисекунды. Другой способ взглянуть на ваш тест: исключение стоит всего в 5 раз больше, чем один оператор if. Если у вас очень большой быстрый цикл, возможно, исключения могут вызвать проблемы с производительностью. Если вы выполняете несколько запросов к БД для HTTP-запроса, разрешение каждому запросу генерировать исключение практически не влияет на производительность.

Daniel Waltrip 23.10.2018 02:03

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

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

В языках программирования существует большой раскол вокруг использования исключений.

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

  • Существует сильное мнение меньшинства о том, что исключения - это просто еще одна конструкция потока управления, и они должны быть дешевыми. Компиляторы Стандартный ML Нью-Джерси и Цель Caml подписываются на это представление. Если у вас дешевые исключения, вы можете закодировать некоторые причудливые алгоритмы отслеживания с возвратом способами, которые труднее кодировать чисто с использованием других механизмов.

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

Вы не поверите, но на самом деле это проблема, которая немного отличается для каждого языка. В Python для событий, которые не являются исключительными для самого языка, регулярно создаются исключения. Таким образом, я думаю, что правило «вы должны выдавать исключения только в исключительных обстоятельствах» не совсем применимо. Я думаю, что результаты, которые вы получите на этом форуме, будут склоняться к этой точке зрения, учитывая большое количество программистов .Net (см. этот вопрос для получения дополнительной информации по этому поводу).

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

+1: Python использует исключения в некоторых ситуациях, которые не являются аномальными. Если он будет простым, то простое лучше, чем сложное (например, поднять StopIteration).

cdleary 04.01.2009 03:14

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

Вот более реалистичный пример использования Django с базой данных sqlite в памяти. Был запущен каждый из 100 различных запросов, а затем усреднено среднее значение для каждого из 100 запусков. Хотя сомневаюсь, что это будет иметь значение, я также изменил порядок исполнения.

With ObjectDoesNotExist... 0.102783939838
Without exception ........ 0.105322141647

With ObjectDoesNotExist... 0.102762134075
Without exception ........ 0.101523952484

With ObjectDoesNotExist... 0.100004930496
Without exception ........ 0.107946784496

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

Другие вопросы по теме