Исключения и классы исключений

Как правило, исключение составляют любые необычные условия. Исключение обычно указывает на ошибки, но иногда они намеренно вводят программу в таких случаях, как преждевременное завершение процедуры или восстановление после нехватки ресурсов. Существует ряд встроенных исключений, которые указывают на такие условия, как чтение после конца файла или деление на ноль. Мы можем определять наши собственные исключения, называемые настраиваемыми исключениями.

Обработка исключений позволяет изящно обрабатывать ошибки и делать с ними что-то значимое. Обработка исключений состоит из двух компонентов: «бросание» и «перехват».

Выявление исключения (ошибок)

Каждая ошибка, возникающая в Python, приводит к исключению, которое будет условием ошибки, идентифицированным по типу ошибки.

>>> #Exception
>>> 1/0
Traceback (most recent call last):
   File "<pyshell#2>", line 1, in <module>
      1/0
ZeroDivisionError: division by zero
>>>
>>> var = 20
>>> print(ver)
Traceback (most recent call last):
   File "<pyshell#5>", line 1, in <module>
      print(ver)
NameError: name 'ver' is not defined
>>> #Above as we have misspelled a variable name so we get an NameError.
>>>
>>> print('hello)

SyntaxError: EOL while scanning string literal
>>> #Above we have not closed the quote in a string, so we get SyntaxError.
>>>
>>> #Below we are asking for a key, that doen't exists.
>>> mydict = {}
>>> mydict['x']
Traceback (most recent call last):
   File "<pyshell#15>", line 1, in <module>
      mydict['x']
KeyError: 'x'
>>> #Above keyError
>>>
>>> #Below asking for a index that didn't exist in a list.
>>> mylist = [1,2,3,4]
>>> mylist[5]
Traceback (most recent call last):
   File "<pyshell#20>", line 1, in <module>
      mylist[5]
IndexError: list index out of range
>>> #Above, index out of range, raised IndexError.

Отлов / Исключение отлова

Когда в вашей программе происходит что-то необычное, и вы хотите обработать это с помощью механизма исключения, вы «генерируете исключение». Ключевые слова try и except используются для перехвата исключений. Всякий раз, когда в блоке try возникает ошибка, Python ищет соответствующий блок except для ее обработки. Если есть, то исполнение перескакивает туда.

синтаксис

try:
   #write some code
   #that might throw some exception
except <ExceptionType>:
   # Exception handler, alert the user

Код в предложении try будет выполняться оператор за оператором.

Если возникает исключение, остальная часть блока try будет пропущена, и будет выполнено предложение except.

try:
   some statement here
except:
   exception handling

Давайте напишем код, чтобы увидеть, что произойдет, если вы не используете в своей программе какой-либо механизм обработки ошибок.

number = int(input('Please enter the number between 1 & 10: '))
print('You have entered number',number)

Вышеупомянутая программа будет работать правильно, пока пользователь вводит число, но что произойдет, если пользователи попытаются ввести какой-либо другой тип данных (например, строку или список).

Please enter the number between 1 > 10: 'Hi'
Traceback (most recent call last):
   File "C:/Python/Python361/exception2.py", line 1, in <module>
      number = int(input('Please enter the number between 1 & 10: '))
ValueError: invalid literal for int() with base 10: "'Hi'"

Теперь ValueError - это тип исключения. Попробуем переписать приведенный выше код с обработкой исключений.

import sys

print('Previous code with exception handling')

try:
   number = int(input('Enter number between 1 > 10: '))

except(ValueError):
   print('Error..numbers only')
   sys.exit()

print('You have entered number: ',number)

Если мы запустим программу и введем строку (вместо числа), мы увидим, что получим другой результат.

Previous code with exception handling
Enter number between 1 > 10: 'Hi'
Error..numbers only

Вызов исключений

Чтобы поднять исключения из ваших собственных методов, вам нужно использовать ключевое слово raise, подобное этому

raise ExceptionClass(‘Some Text Here’)

Возьмем пример

def enterAge(age):
   if age<0:
      raise ValueError('Only positive integers are allowed')
   if age % 2 ==0:
      print('Entered Age is even')
   else:
      print('Entered Age is odd')

try:
   num = int(input('Enter your age: '))
   enterAge(num)
except ValueError:
   print('Only positive integers are allowed')

Запустите программу и введите положительное целое число.

Ожидаемый результат

Enter your age: 12
Entered Age is even

Но когда мы пытаемся ввести отрицательное число, мы получаем

Ожидаемый результат

Enter your age: -2
Only positive integers are allowed

Создание собственного класса исключения

Вы можете создать собственный класс исключения, расширив класс или подкласс BaseException от BaseException.

На диаграмме выше мы видим, что большинство классов исключений в Python расширяется от класса BaseException. Вы можете получить свой собственный класс исключения из класса BaseException или его подкласса.

Создайте новый файл с именем NegativeNumberException.py и напишите следующий код.

class NegativeNumberException(RuntimeError):
   def __init__(self, age):
      super().__init__()
      self.age = age

Приведенный выше код создает новый класс исключения с именем NegativeNumberException, который состоит только из конструктора, который вызывает конструктор родительского класса с помощью super () __ init __ () и устанавливает возраст.

Теперь, чтобы создать свой собственный класс исключения, напишем код и импортируем новый класс исключения.

from NegativeNumberException import NegativeNumberException
def enterage(age):
   if age < 0:
      raise NegativeNumberException('Only positive integers are allowed')

   if age % 2 == 0:
      print('Age is Even')

   else:
      print('Age is Odd')

try:
   num = int(input('Enter your age: '))
   enterage(num)
except NegativeNumberException:
   print('Only positive integers are allowed')
except:
   print('Something is wrong')

Вывод

Enter your age: -2
Only positive integers are allowed

Другой способ создать собственный класс Exception.

class customException(Exception):
   def __init__(self, value):
      self.parameter = value

   def __str__(self):
      return repr(self.parameter)
try:
   raise customException('My Useful Error Message!')
except customException as instance:
   print('Caught: ' + instance.parameter)

Вывод

Caught: My Useful Error Message!

Иерархия исключений

Иерархия классов для встроенных исключений -

+-- SystemExit 
+-- KeyboardInterrupt 
+-- GeneratorExit 
+-- Exception 
+-- StopIteration 
+-- StopAsyncIteration 
+-- ArithmeticError 
| +-- FloatingPointError 
| +-- OverflowError 
| +-- ZeroDivisionError 
+-- AssertionError 
+-- AttributeError 
+-- BufferError 
+-- EOFError 
+-- ImportError 
+-- 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 
+-- SyntaxError 
| +-- IndentationError
| +-- TabError 
+-- SystemError 
+-- TypeError 
+-- ValueError 
| +-- UnicodeError 
| +-- UnicodeDecodeError 
| +-- UnicodeEncodeError 
| +-- UnicodeTranslateError 
+-- Warning 
+-- DeprecationWarning 
+-- PendingDeprecationWarning 
+-- RuntimeWarning 
+-- SyntaxWarning 
+-- UserWarning 
+-- FutureWarning 
+-- ImportWarning 
+-- UnicodeWarning 
+-- BytesWarning 
+-- ResourceWarning