Лучше ли использовать исключение или код возврата в Python?
Вы можете знать эту рекомендацию от Microsoft об использовании исключений в .NET:
Оценка производительности
...
Выбросить исключения только для чрезвычайные условия,...
Кроме того, не бросайте исключение когда код возврата достаточен...
(см. весь текст http://msdn.microsoft.com/en-us/library/system.exception.aspx.)
Как точка сравнения, вы бы порекомендовали то же самое для кода Python?
Ответы
Ответ 1
Пифонов нужно делать, чтобы поднимать и обрабатывать исключения. Отличная книга "Python в двух словах" обсуждает это в "Стратегии проверки ошибок" в главе 6.
В книге обсуждается EAFP ( "проще просить прощения, чем разрешение" ) по сравнению с LBYL ( "посмотрите, прежде чем прыгать" ).
Итак, чтобы ответить на ваш вопрос:
Нет, я бы не рекомендовал то же самое для кода python. Я предлагаю вам прочитать главу 6 Python в двух словах.
Ответ 2
Лучший способ понять исключения - " если ваш метод не может сделать то, что говорит его имя, бросьте." Мое личное мнение состоит в том, что этот совет должен применяться одинаково как для .NET, так и для Python.
Основное различие заключается в том, что у вас есть методы, которые часто не могут выполнять то, что их имя говорит, что они должны делать, например, анализировать строки как целые числа или извлекать запись из базы данных. Стиль С# заключается в том, чтобы избежать исключения в первую очередь:
int i;
if (Int32.TryParse(myString, out i)) {
doWhatever(i);
}
else {
doWhatever(0);
}
в то время как Python гораздо удобнее в этом:
try:
i = int(myString)
except ValueError:
i = 0
doWhatever(i);
Ответ 3
В исключениях Python не так дорого, как на некоторых других языках, поэтому я бы не рекомендовал избегать исключений. Но если вы делаете исключение, вы обычно захотите поймать его где-нибудь в своем коде, исключение будет, если произойдет фатальная ошибка.
Ответ 4
Обычно Python ориентирован на выразительность.
Я бы применил тот же принцип здесь: обычно вы ожидаете, что функция вернет результат (в соответствии с его именем!), А не код ошибки.
По этой причине обычно лучше создавать исключение, чем возвращать код ошибки.
Однако то, что указано в статье MSDN, относится и к Python, и оно действительно не связано с возвратом кода ошибки вместо исключения.
Во многих случаях вы можете увидеть обработку исключений, используемых для нормального управления потоком, и для обработки ожидаемых ситуаций. В определенных средах это оказывает огромное влияние на производительность; во всех средах он оказывает большое влияние на выразительность и ремонтопригодность программы.
Исключения для исключительных ситуаций, которые находятся вне нормального потока программы; если вы ожидаете, что что-то произойдет, тогда вы должны обращаться напрямую, а затем поднимать все, чего вы не можете ожидать/обрабатываете.
Конечно, это не рецепт, а только эвристика; окончательное решение всегда зависит от разработчика и от контекста и не может быть указано в фиксированном наборе руководств - и это гораздо более верно для обработки исключений.
Ответ 5
Я сделал простой эксперимент, чтобы сравнить производительность по сбору исключений со следующим кодом:
from functools import wraps
from time import time
import logging
def timed(foo):
@wraps(foo)
def bar(*a, **kw):
s = time()
foo(*a, **kw)
e = time()
print '%f sec' % (e - s)
return bar
class SomeException(Exception):
pass
def somefunc(_raise=False):
if _raise:
raise SomeException()
else:
return
@timed
def test1(_reps):
for i in xrange(_reps):
try:
somefunc(True)
except SomeException:
pass
@timed
def test2(_reps):
for i in xrange(_reps):
somefunc(False)
def main():
test1(1000000)
test2(1000000)
pass
if __name__ == '__main__':
main()
Со следующими результатами:
- Исключение исключений: 3.142000 sec
- Использование
return
: 0.383000 сек
Исключения примерно в 8 раз медленнее, чем при использовании return
.
Ответ 6
Я думаю, что вернуть код ошибки или выбросить исключение - это что-то очень действительное, о чем можно подумать, и кросс-лингвистическое сравнение может быть полезным и информативным. Я думаю, что очень обобщенный ответ на эту озабоченность - это просто рассмотрение: набор допустимых значений возврата для любой функции должен быть сделан как можно меньше и насколько это необходимо.
Как правило, это будет означать, что если данный метод возвращает целое число в одном тестовом случае, пользователи могут по праву ожидать, что метод всегда возвращает целочисленный номер или генерирует исключение. Но, конечно, концептуально простой способ - это не всегда лучший способ справиться с вещами.
Возвращаемое значение наименьшего сюрприза обычно None
; и если вы посмотрите на него, вы увидите, что его семантика None
, которая лицензирует его использование по всем направлениям: это одноэлементное неизменяемое значение, которое во многих случаях оценивается как False
или запрещает дальнейшие вычисления -не конкатенации, без арифметики. Поэтому, если вы решили написать метод frob(x)
, который возвращает число для ввода строки, и None
для нечисловых строк и любого другого ввода, и вы используете это внутри выражения типа a=42+frob('foo')
, вы все равно получаете исключение очень близко к точке, в которой произошло фиктивное действие. Конечно, если вы введете frob('foo')
в столбец базы данных, который не был определен с помощью NOT NULL
, вы можете столкнуться с проблемами, возможно, через несколько месяцев. Это может быть или не быть оправданным.
Поэтому в большинстве случаев, когда вы, например, хотите вывести число из строки, используя что-то вроде bare float(x)
или int(x)
, это путь, так как эти встроенные модули будут создавать исключение, если не заданы усредняемые данные. Если это не подходит для вашего использования, подумайте о возврате None
из пользовательского метода; в основном, это возвращаемое значение говорит потребителям, что "Извините, я не смог понять ваш вклад. Но вы только хотите это сделать, если вы положительно знаете, что в вашей программе есть смысл с этой точки зрения и далее.
Видите ли, я только что узнал, как превратить каждое уведомление, предупреждение и сообщение об ошибке в потенциально исключение show-stopping в, м, PHP. Это просто сводит меня с ума, что опечатка в имени переменной генерируется в стандартной конфигурации PHP, ничего, кроме уведомления пользователя. Это , поэтому плохо. Программа просто продолжает делать что-то с программным кодом, который не имеет смысла вообще! Я не могу поверить, что люди находят эту особенность.
Точно так же следует рассматривать его так: если в любой момент времени можно с достаточной обоснованностью утверждать, что выполнение части кода больше не имеет смысла - поскольку значения отсутствуют, выходят из или неожиданный тип, или когда такие ресурсы, как соединение с базой данных, снизились - крайне важно минимизировать головные боли отладки, нарушить выполнение и ручное управление до любого уровня в коде, который имеет право обрабатывать неудачу.
Опыт показывает, что воздержание от раннего действия и возможность подталкивания фиктивных значений к вашим данным ни к чему, кроме того, что ваш код сложнее отлаживать. Так много примеров чрезмерно усердного литья типов: позволяет добавлять целые числа к плавающим элементам. Чтобы строка, содержащая только цифры, добавляемые в число, является фиктивной практикой, которая может создавать странные, нелокализованные ошибки, которые могут появляться на любой заданной строке, которая обрабатывает эти данные.