Все ошибки в языке Python делятся на два типа:
- синтаксические ошибки;
- исключения - ошибки, которые возникают в процессе исполнения кода.
Когда мы запускаем файл целиком на исполнение, то интерпретатор для начала проверяет его полностью на синтаксические ошибки. Синтаксические ошибки - это единственные ошибки о которых можно узнать до исполнения самого кода.
Ошибки также являются объектами и поэтому у любой ошибки есть тип:
- IndexError - мы пытались взять индекс, которого нет в списке.
- NameError - это такая ошибка, которая встречается, когда мы не можем найти имя в пространстве имен.
- TypeError - мы вероятно передали в какую-нибудь функцию, что-нибудь неправильного типа.
Ошибка хранит в себе состояние стека вызова на тот момент, когда совершилась ошибка.
Внутри блока try на самом деле генерируется объект исключения. У этого объекта нет имени, однако где-то у нас есть такой объект e, его не существует ни в каком неймспейсе.
Мы используем isinstance, а не сравнение типов через type потому что все ошибки в языке Python представляют собой иерархию. ZeroDivisionError наследуется от класса ArithmeticError, т.е. он является арифметической ошибкой:
Из-за использования функции isinstance никогда не имеет смысла проверять наследника внутри одного except-блока после предка в except-блоке выше:
Когда мы пишем несколько except блоков важно помнить, что любое исключение будет обработано лишь одним из них - первым под которое оно подойдет.
Мы можем ловить наши исключения в любой момент исполнения на стеке:
Одним except-блоком можно поймать сразу несколько типов исключений:
Также можно поймать и сам объект ошибки:
Можно исполнить try-except-блок без указания конкретных типов исключений, которые можно ловить:
Ключевое слово else используется, когда внутри try-блока не возникло никакого исключения и мы возможно хотим что-то сделать в этом случае. А блок finally запускается в любом случае.
Все исключения, которые мы ловим с помощью except и бросаем с помощью raise должны быть экземплярами BaseException.
Можно написать свой собственный класс исключений:
Как ловить (catch) исключения
Некоторую часть ошибок можно поймать и обработать:try: x = [1, 2, "hello", 7] x.sort() print(x) except TypeError: print("Type error :(") print("I can catch")
Внутри блока try на самом деле генерируется объект исключения. У этого объекта нет имени, однако где-то у нас есть такой объект e, его не существует ни в каком неймспейсе.
try: 15 / 0 # e except ZeroDivisionError: # isinstance(e, ZeroDivisionError) == True print("Division by zero")
>>> print(ZeroDivisionError.mro()) [<class 'ZeroDivisionError'>, <class 'ArithmeticError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>]
try: 15 / 0 # e except ZeroDivisionError: # isinstance(e, ZeroDivisionError) == True print("Division by zero") except ZeroDivisionError: # не имеет смысла, т.к. все арифметические ошибки мы поймали выше print("zero division") print(ZeroDivisionError.mro())
Когда мы пишем несколько except блоков важно помнить, что любое исключение будет обработано лишь одним из них - первым под которое оно подойдет.
def f(x,y): try: return x / y except TypeError: print("Type error") except ZeroDivisionError: print("Zero division :(") f(5, "123") print(f(5,0))
Мы можем ловить наши исключения в любой момент исполнения на стеке:
def f(x,y): try: return x / y except TypeError: print("Type error") f(5, "123") try: print(f(5,0)) except ZeroDivisionError: print("Zero division :(")
Одним except-блоком можно поймать сразу несколько типов исключений:
def f(x,y): try: return x / y except (TypeError, ZeroDivisionError): print("Error :(") print(f(5,0)) print(f(5,[]))
Также можно поймать и сам объект ошибки:
def f(x,y): try: return x / y except (TypeError, ZeroDivisionError) as e: print(type(e)) print(e) print(e.args) print(f(5,0)) print(f(5,[]))
Можно исполнить try-except-блок без указания конкретных типов исключений, которые можно ловить:
def f(x,y): try: return x / y except: # поймает любую ошибку print("Error :(") print(f(5,0)) print(f(5,[]))
Ключевое слово else используется, когда внутри try-блока не возникло никакого исключения и мы возможно хотим что-то сделать в этом случае. А блок finally запускается в любом случае.
def divide(x, y): try: result = x / y except ZeroDivisionError: print("division by zero") else: # если не будет никакого исключения print("result is", result) finally: # просто выведем строку "finally" print("finally") divide(2, 1) divide(2, 0) divide(2, [])
Как бросать (throw) исключения
Для того чтобы бросить исключение в языке Python необходимо использовать конструкцию rise, в которую нужно передать объект нашего исключения.def greet(name): if name[0].isupper(): return "Hello, " + name else: raise ValueError(name + " is inappropriate name") print(greet("Abdullah")) print(greet("abdullah")) # а неприличные люди получат ошибку
Все исключения, которые мы ловим с помощью except и бросаем с помощью raise должны быть экземплярами BaseException.
Можно написать свой собственный класс исключений:
class BadName(Exception): pass def greet(name): if name[0].isupper(): return "Hello, " + name else: raise BadName(name + " is inappropriate name") while True: try: name = input("Please enter your name: ") greeting = greet(name) print(greeting) except ValueError: print("Please try again") else: break
Комментариев нет:
Отправить комментарий