У чому причина спроби, окрім іншого, існувати?
try
Блок дозволяє обробляти очікувану помилку. except
Блок повинен зловити тільки виключення ви готові до обробки. Якщо ви обробляєте несподівану помилку, ваш код може зробити неправильну справу та приховати помилки.
else
Пункт буде виконуватися , якщо не було ніяких помилок, і не виконує цей код в try
блоці, ви уникнете зловити несподівану помилку. Знову ж таки, виявлення несподіваної помилки може приховати помилки.
Приклад
Наприклад:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
else:
return something
У наборі "спробувати, за винятком" є два необов'язкові пропозиції else
та finally
. Так це насправді try-except-else-finally
.
else
буде оцінюватися лише в тому випадку, якщо з try
блоку немає винятку . Це дозволяє нам спростити більш складний код нижче:
no_error = None
try:
try_this(whatever)
no_error = True
except SomeException as the_exception:
handle(the_exception)
if no_error:
return something
тому, якщо порівнювати a else
з альтернативою (яка може створювати помилки), ми бачимо, що вона скорочує рядки коду, і ми можемо мати більш читабельну, підтримувану та менш баггічну базу коду.
finally
finally
буде виконуватися незважаючи ні на що, навіть якщо інший рядок оцінюється випискою return.
Розбитий псевдокодом
Це може допомогти розбити це в найменшій формі, що демонструє всі функції, з коментарями. Припустимо, цей синтаксично правильний (але не піддається виконанню, якщо не визначені імена) псевдо-код функціонує.
Наприклад:
try:
try_this(whatever)
except SomeException as the_exception:
handle_SomeException(the_exception)
# Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
generic_handle(the_exception)
# Handle any other exception that inherits from Exception
# - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
# Avoid bare `except:`
else: # there was no exception whatsoever
return something()
# if no exception, the "something()" gets evaluated,
# but the return will not be executed due to the return in the
# finally block below.
finally:
# this block will execute no matter what, even if no exception,
# after "something" is eval'd but before that value is returned
# but even if there is an exception.
# a return here will hijack the return functionality. e.g.:
return True # hijacks the return in the else clause above
Це правда, що ми могли б замість цього включити код до else
блоку try
, де він би запускався, якби не було винятків, але що робити, якщо цей код сам по собі створює виняток із типу, який ми ловимо? Залишивши його в try
блоці, він би приховав цю помилку.
Ми хочемо мінімізувати рядки коду в try
блоці, щоб уникнути винятків, яких ми не очікували, відповідно до принципу, що якщо наш код виходить з ладу, ми хочемо, щоб він гучно вийшов з ладу. Це найкраща практика .
Як я розумію, винятки - це не помилки
У Python більшість винятків - це помилки.
Ми можемо переглянути ієрархію винятків, використовуючи pydoc. Наприклад, у Python 2:
$ python -m pydoc exceptions
або Python 3:
$ python -m pydoc builtins
Дасть нам ієрархія. Ми можемо бачити, що більшість видів Exception
є помилками, хоча Python використовує деякі з них для таких речей, як закінчення for
циклів ( StopIteration
). Це ієрархія Python 3:
BaseException
Exception
ArithmeticError
FloatingPointError
OverflowError
ZeroDivisionError
AssertionError
AttributeError
BufferError
EOFError
ImportError
ModuleNotFoundError
LookupError
IndexError
KeyError
MemoryError
NameError
UnboundLocalError
OSError
BlockingIOError
ChildProcessError
ConnectionError
BrokenPipeError
ConnectionAbortedError
ConnectionRefusedError
ConnectionResetError
FileExistsError
FileNotFoundError
InterruptedError
IsADirectoryError
NotADirectoryError
PermissionError
ProcessLookupError
TimeoutError
ReferenceError
RuntimeError
NotImplementedError
RecursionError
StopAsyncIteration
StopIteration
SyntaxError
IndentationError
TabError
SystemError
TypeError
ValueError
UnicodeError
UnicodeDecodeError
UnicodeEncodeError
UnicodeTranslateError
Warning
BytesWarning
DeprecationWarning
FutureWarning
ImportWarning
PendingDeprecationWarning
ResourceWarning
RuntimeWarning
SyntaxWarning
UnicodeWarning
UserWarning
GeneratorExit
KeyboardInterrupt
SystemExit
Коментолог запитав:
Скажімо, у вас є метод, який записує зовнішній API, і ви хочете обробити виняток у класі поза обгорткою API, ви просто повертаєте e з методу за винятком пункту, де e об'єкт виключення?
Ні, ви не повертаєте виняток, просто перейміть його голими, raise
щоб зберегти стек-трек.
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise
Або в Python 3 ви можете створити новий виняток і зберегти backtrace з ланцюжком виключень:
try:
try_this(whatever)
except SomeException as the_exception:
handle(the_exception)
raise DifferentException from the_exception
Я деталізую тут свою відповідь .