betacode

Руководство по исключению Python

  1. Что такое Exception?
  2. Иерархия исключений
  3. Обработка исключений через try-except
  4. Блок try-except-finally
  5. Перевыбросить исключение
  6. Обернуть Exception в другом Exception 

1. Что такое Exception?

Для начала посмотрим следующий иллюстрированный пример:
В данном примере есть код с ошибкой по причине деления на 0. Из-за деления на 0 происходит исключение: ZeroDivisionError
helloExceptionExample.py
print ("Three")

# This division no problem.
value = 10 / 2 
print ("Two")

# This division no problem.
value = 10 / 1 
print ("One")

d = 0

# This division has problem, divided by 0.
# An error has occurred here.
value = 10 / d

# And the following code will not be executed.
print ("Let's go!")
Результат запуска примера:
Вы можете увидеть уведомление ошибки на экране Console, уведомление ошибки очень понятное, на какой строке кода это произошло.
Посмотрим потом программы на изображении ниже.
  • Программа запущена как обычно с шагов (1),(2) до (6)
  • В шаге (7) происходит проблема при делении на 0. Программа завершается.
  • В шаге (8) код не был выполнен.
Мы изменим код в примере выше.
helloCatchException.py
print ("Three")

value = 10 / 2

print ("Two")

value = 10 / 1
 
print ("One")

d = 0 

try :
    # Это деление имеет проблему, деление на 0.
    # Здесь происходит ошибка (ZeroDivisionError).
    value = 10 / d 
    print ("value = ", value) 
except ZeroDivisionError as e : 
    print ("Error: ", str(e) )
    print ("Ignore to continue ...") 

print ("Let's go!")
И результаты запуска примера:
Three
Two
One
Error division by zero
Ignore to coninue ...
Let's go!
Мы объясним используя иллюстрацию ниже о потоке программы.
  • Шаги (1)-(6) совершенно нормальны.
  • Исключение происходит в шаге (7), проблема при делении на 0.
  • Сразу он перепрыгивает на выполнение команды в блоке except, шаг (8) пропускается.
  • Шаги (9), (10) выполняются.
  • Шаг (11) выполняется.

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

This is the model of hierarchical map of Exception in Python.
  • Самый высший класс это BaseException
  • Прямыми подклассами являются Exception и KeyboardInterrupt, ..
Готовые Exception в Python обычно получены из (derived) BaseException (Расширены из BaseException). В то время как exception пользвателя (программиста) должны быть унаследованы из класса Exception или из его подкласса.

3. Обработка исключений через try-except

Мы напишем класс exception унаследованный из класса Exception.
Функция checkAge для проверки возраста, если возраст меньше 18 или больше 40, выбрасывается исключение.
ageexception.py
# Python 3.x 
class AgeException(Exception): 
    def __init__(self, msg, age ):
        super().__init__(msg) 
        self.age = age 
        
class TooYoungException(AgeException): 
    def __init__(self, msg, age):
        super().__init__(msg, age)     

class TooOldException(AgeException): 
    def __init__(self, msg, age):
        super().__init__(msg, age)    
         
# Функция проверки возраста, может выбросить исключение.
def checkAge(age): 
    if (age < 18) :
        # Если возраст менее 18, выбросится исключение.
        # Фукнция завершится здесь.
        raise TooYoungException("Age " + str(age) + " too young", age) 
    elif (age > 40) :
        # Если возраст старше 40, выбросится исключение.
        # Фукнция завершится здесь.       
        raise TooOldException("Age " +  str(age) + " too old", age); 
    # Если возраст в рамках 18-40.
    # Этот код будет выполнен.
    print ("Age " +  str(age) + " OK!");
Пример:
tryExceptDemo1.py
import ageexception
from ageexception import AgeException
from ageexception import TooYoungException
from ageexception import TooOldException

print ("Start Recruiting ...")
age = 11
print ("Check your Age ", age)
try : 
    ageexception.checkAge(age)
    print ("You pass!")  
except TooYoungException as e  : 
    print("You are too young, not pass!")    
    print("Cause message: ", str(e) )
    print("Invalid age: ", e.age) 
except  TooOldException as e : 
    print ("You are too old, not pass!")
    print ("Cause message: ", str(e) )
    print("Invalid age: ", e.age)
Запуск примера:
Start Recruiting ...
Check you Age 11
You are too young, not pass!
Cause message: Age 11 too young
Invalid age: 11
В примере ниже, мы обработаем все собранные исключения на уровне выше. На уровне выше обработаются все эти исключения и унаследованные исключения.
tryExceptDemo2.py
import ageexception
from ageexception import AgeException
from ageexception import TooYoungException
from ageexception import TooOldException

print ("Start Recruiting ...")
age = 51 
print ("Check your Age ", age)
try : 
    ageexception.checkAge(age)
    print ("You pass!") 
except AgeException as e  : 
    print("You are not pass!")  
    print("type(e): ", type(e) )
    print("Cause message: ", str(e) )
    print("Invalid age: ", e.age)
Output:
Start Recruiting ...
Check you Age 51
You are not pass!
type(e): <class 'ageexceptioon.TooOldException'>
Cause message: Age 51 too old
Invalid age: 51

4. Блок try-except-finally

Выше мы ознакомились с обработкой исключений через блок try-except. Полная обработка исключения использует try-except-finally. Блок finally всегда выполняется, несмотря не то, происходит исключение в блоке try или нет.
try - except - finally
try : 
    # Сделать что-то здесь.
except Exception1 as e : 
    # Сделать что-то здесь.
except Exception2 as e : 
    # Сделать что-то здесь.
finally : 
    # Блок finally всегда выполняется.
    # Сделать что-то здесь.
Пример:
tryExceptFinallyDemo.py
def toInteger(text) : 
    try :  
        print ("-- Begin parse text: ", text) 
        # Исключение может быть выброшено здесь (ValueError).
        value = int(text) 
        return value 
    except ValueError as e : 
        # В случае 'text' не является числом.
        # Блок 'except' будет выполнен.          
        print ("ValueError message: ", str(e))
        print ("type(e): ", type(e)) 
        # Возвращает 0 если появляется ошибка ValueError.
        return 0  
    finally :  
        print ("-- End parse text: " + text)  
 
text = "001234A2" 
value = toInteger(text) 
print ("Value= ", value)
Запуск примера:
-- Begin parse text: 001234A2
ValueError message: invalid literal for int() with base 10: '001234A2'
type(e): <class 'ValueError'>
-- End parse text: 001234A2
Value= 0
Это поток программы. Блок finally всегда выполняется.
Команда pass
Если ничего не хотите обрабатывать в блоке 'except' или 'finally' вы можете использовать команду 'pass' (pass statement). Команда pass ничего не делает, она похожа на команду null.
passStatementExample.py
print ("Three")
try :
    value = 10 / 0;
except Exception as e:
    pass

print ("Two")  
print ("One")
print ("Let's go")
Output:
Three
Two
One
Let's go

5. Перевыбросить исключение

При обработке исключения вы можете словить это исключение и обработать или перевыбросить (rethrow) его наружу.
reRaiseExceptionDemo1.py
def checkScore(score) :
    if score < 0 or score > 100:
        raise Exception("Invalid Score " + str(score) )

def checkPlayer(name, score):
    try :
        checkScore(score)
    except Exception as e :
        print ("Something invalid with player: ",name, ' >> ', str(e) )
        # re throw exception.
        raise   
# ------------------------------------------ 
checkPlayer("Tran", 101)
Например, словить инсключение и перевыбросить (rethrow) другое исключение.
reRaiseExceptionDemo2.py
def checkScore(score) :  
    if score < 0 or score > 100:
        raise Exception("Invalid Score " + str(score) )

def checkPlayer(name, score):
    try :
        checkScore(score)
    except Exception as e :
        print ("Something invalid with player: ",name, ' >> ', str(e) )
        # throw new exception.
        raise Exception("Something invalid with player: "+ name + " >> "+ str(e)) 

# ------------------------------------------ 
checkPlayer("Tran", 101)

6. Обернуть Exception в другом Exception 

Python позволяет ловить иключение, и выбрасывать новое исключение, новое исключение может хранить информацию начального исключения, в который вы можете иметь доступ через атрибут __cause__.
Syntax
try : 
    # Сделать что-то здесь....
except Exception as e : 
    raise OtherException("Message...") from e
Смотрите полный пример:
wrapExceptionDemo.py
# Python 3.x:
# Исключение пола.
class GenderException(Exception): 
    def __init__(self, msg):
        super().__init__(msg)     

# Исключение языка.
class LanguageException(Exception): 
    def __init__(self, msg):
        super().__init__(msg)     


class PersonException(Exception): 
    def __init__(self, msg):
        super().__init__(msg)

# Эта функция может выбросить GenderException.
def checkGender(gender): 
    if gender != 'Female' :
        raise GenderException("Accept female only")

# Эта функция может выбросить LanguageException.
def checkLanguage(language):   
    if language != 'English' :
        raise LanguageException("Accept english language only") 

def checkPerson(name, gender, language): 
    try : 
        # Может выбросить GenderException.
        checkGender(gender)
        # Может выбросить LanguageException.
        checkLanguage(language)
    except Exception as e:
        # Ловит exception и выбрасывает другие исключения.
        # Новое исключение имеет информацию __cause__ = e.
        raise PersonException(name + " does not pass") from e
    
# -------------------------------------------------------- 
try  : 
    checkPerson("Nguyen", "Female", "Vietnamese") 
except PersonException as e: 
    print ("Error message: ", str(e) )    
    # GenderException или LanguageException
    cause = e.__cause__   
    print ('e.__cause__: ', repr(cause)) 
    print ("type(cause): " , type(cause) ) 
    print (" ------------------ ")
    
    if type(cause) is GenderException : 
        print ("Gender exception: ", cause) 
    elif type(cause) is LanguageException: 
        print ("Language exception: ", cause)
Output:
Error message: Nguyen does not pass
e.__cause__: LanguageException('Accept english language only',)
type(cause): <class '__main__.LanguageException'>
 ------------------
Language exception: Accept english language only