функция должна возвращать результат или сообщить, что не может вычислит. Как сделать красиво и правильно?
я новичек в питоне, но подобный вопрос возникал раньше с другими языкам, и я не нашел пока подходящего мне решения.
вопрос не конкретный - интересует общий подход к реализации:
Некая функция вычисляет нечто, и есть два результата вычисления -
- Вычисление выполнено - вернуть результат.
- Результат вычисления не подходит - тогда результат не интересен, но нужно передать сообщение выше по иерархии вызовов.
Я придумал пока только три варианта реализации- ни один мне не нравится:
в случае неудачи вернуть False или None и уже при вызове функции разобраться с выдачей сообщения.
def MyFunction(): # ... result = someCalculation() # ... if result == SOMTHING_UNFIT: return False else: return result # ... result = MyFunction() if result == False: print 'Вычисление закончено. Результат не получен.' else: DoSomething(result)в случае неудачи выбросить исключение и поймать его, там где нужно
def MyFunction(): # ... result = someCalculation() # ... if result == SOMTHING_UNFIT: raise MyException('Вычисление закончено. Результат не получен.') else: return result # ... try: result = MyFunction() except MyException as e: print(e.args) DoSomething(result)Вернуть словарь, с несолькоми полями
def MyFunction(): # ... result = someCalculation() # ... if result == SOMTHING_UNFIT: return { 'fit': False, 'message': 'Вычисление закончено. Результат не получен.', 'result': None, } else: return { 'fit': True, 'message': None, 'result': result, } # ... result_dict = MyFunction() if result_dict['fit'] == False print(result_dict['message']) else: DoSomething(result_dict['result'])
Чем мне не нравятся эти решения:
- возвращаемое значени используется в двух целях - как выдача результата и как индикатор успешности выполнения вычисления. мне кажется, что это неправильно.
- выдается куча сообщений, но на самом деле это не исключения, или ошибки - это штатный вариант иногда результат можно вычислить, а иногда нет...
- сильно громоздко, и одни поля не используются в одном случае, а другие в другом
Вопросы:
- Оптимальный вариант реализации, как это обычно делается (шаблон проектирования?)
- есть ли какой-нибудь механизм передать сообщение наверх напрямую (сквозь цепочки вызовов функций, циклы) - типа исключения, но без сообшений об ошибках... вроде какой-нибудь GOTO, аспект, декоратор, DI контейнер, mixin? магия?
Ответы (3 шт):
По-моему вариант с возвратом None самый нормальный если вы считаете, что это не исключительная ситуация. Если это исключительная ситуация - тогда надо выбрасывать исключение (Exception).
Значение None - необычное значение, которое не должно возвращаться в нормальном случае.
Кроме того, возвращаемое значение легко проверить на None:
res = func(...)
if res is None:
...
В зависимости от необходимого поведения, можно добавить logging и печатать предупреждения (warning).
Традиционно, для решения проблемы с возвратом при ошибке, в Python используется простой приём: функция возвращает 2 значения - результат своей работы и признак наличия ошибки. Как то так:
if .... :
# Всё хорошо
return result, False
else:
return None, True
А в вызывающей программе пишите:
(x, error) = MyFunction(...)
if error:
....
На самом деле все варианты вполне нормальные. Про нюансы других вариантов написали уже в других ответах, а я хочу сказать про исключения. Вас ведь никто не заставляет печатать пойманное исключение MyException. Вы можете просто пробрасывать именно это исключение насколько вам нужно наверх, и только где-то наверху что-то вывести, да и то, если вам это нужно. Это просто механизм возврата управления выше по цепочке, если возникла такая необходимость.