Этот конкретный пример относится к 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 фильтр и обработать список самостоятельно?






Подсказка кроется в названии - исключения должны быть исключительными.
Если вы всегда ожидаете, что элемент будет существовать, используйте 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.
Для записи, оба этих примера вызывают исключение StopIteration. ИМО это показывает, что исключения НЕ оказывают существенного влияния на производительность при разумном использовании.
a [1] выдаст вам IndexError. Итерация продолжается, потому что исключение перехватывается и передается в цикле. Я утверждаю, что мой пример действителен, поскольку показывает, что переданные исключения в цикле могут снизить производительность (в данном случае 5x).
Это неверно. В контексте вопроса значимой проблемы с производительностью нет. Ваш тест выполняет 1 миллион итераций, а версия с исключениями заняла 3,5 секунды. Это означает, что стоимость каждого исключения составляет примерно 0,0035 миллисекунды. Другой способ взглянуть на ваш тест: исключение стоит всего в 5 раз больше, чем один оператор if. Если у вас очень большой быстрый цикл, возможно, исключения могут вызвать проблемы с производительностью. Если вы выполняете несколько запросов к БД для HTTP-запроса, разрешение каждому запросу генерировать исключение практически не влияет на производительность.
Отвращение к исключениям - это вопрос общественного мнения, однако, если есть основания полагать, что функция или метод будет вызываться много раз или вызываться быстро, исключения вызовут значительное замедление. Я узнал об этом из своего предыдущий вопрос, где раньше я полагался на выброшенное исключение для возврата значения по умолчанию, а не на проверку параметров для возврата этого значения по умолчанию.
Конечно, исключения все еще могут существовать по любой причине, и вы не должны бояться использовать или выбросить их при необходимости - особенно те, которые потенциально могут нарушить нормальный поток вызывающей функции.
В языках программирования существует большой раскол вокруг использования исключений.
Большинство считает, что исключения должны быть исключительными. В большинстве языков, за исключением исключений, передача управления по исключению значительно дороже, чем, например, по возврату процедуры.
Существует сильное мнение меньшинства о том, что исключения - это просто еще одна конструкция потока управления, и они должны быть дешевыми. Компиляторы Стандартный ML Нью-Джерси и Цель Caml подписываются на это представление. Если у вас дешевые исключения, вы можете закодировать некоторые причудливые алгоритмы отслеживания с возвратом способами, которые труднее кодировать чисто с использованием других механизмов.
Я видел, как эта дискуссия повторялась много раз для новых языковых дизайнов, и почти всегда победитель решает, что исключения должны быть дорогими и редкими. Когда вы заботитесь о производительности, было бы разумно запрограммировать это с учетом этого.
Вы не поверите, но на самом деле это проблема, которая немного отличается для каждого языка. В Python для событий, которые не являются исключительными для самого языка, регулярно создаются исключения. Таким образом, я думаю, что правило «вы должны выдавать исключения только в исключительных обстоятельствах» не совсем применимо. Я думаю, что результаты, которые вы получите на этом форуме, будут склоняться к этой точке зрения, учитывая большое количество программистов .Net (см. этот вопрос для получения дополнительной информации по этому поводу).
Как минимум, мне лучше не ловить тех, кто придерживается этого правила, когда-либо использующих генератор или цикл for в Python (оба из которых включают выброс исключений для неисключительных обстоятельств).
+1: Python использует исключения в некоторых ситуациях, которые не являются аномальными. Если он будет простым, то простое лучше, чем сложное (например, поднять StopIteration).
Я не согласен с приведенными выше комментариями о том, что исключение неэффективно в этом случае, особенно потому, что оно используется в связанной операции ввода-вывода.
Вот более реалистичный пример использования 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, но я сомневаюсь, что ваше время потрачено не зря, избегая этого исключения.
Можете ли вы предоставить некоторые измерения, сравнивающие версии с исключениями и без исключения? Хотелось бы посмотреть, насколько велико это "заметное" попадание на самом деле.