Статьи

Обработка ошибок и ведение журнала в Python

При разработке программного обеспечения могут возникать различные типы ошибок. Это могут быть синтаксические ошибки, логические ошибки или ошибки времени выполнения.

Синтаксические ошибки, скорее всего, возникают на начальном этапе разработки и являются результатом неправильного синтаксиса. Синтаксические ошибки могут быть легко обнаружены при компиляции программы для выполнения.

Логические ошибки, с другой стороны, являются результатом неправильной логической реализации. Примером может служить программа, обращающаяся к несортированному списку в предположении, что он отсортирован. Логические ошибки являются наиболее сложными для отслеживания.

Ошибки во время выполнения — самые интересные ошибки, которые возникают, если мы не рассматриваем все угловые случаи. Примером будет попытка получить доступ к несуществующему файлу.

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

Давайте начнем с простой программы для добавления двух чисел в Python. Наша программа принимает в качестве входных данных два параметра и выводит сумму. Вот программа на Python для добавления двух чисел:

1
2
3
4
def addNumbers(a, b):
    print a + b
 
addNumbers(5, 10)

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

1
15

При написании вышеупомянутой программы мы не учитывали тот факт, что что-то может пойти не так. Что если один из переданных параметров не является числом?

1
addNumbers(», 10)

Мы не обработали этот случай, поэтому наша программа вылетала со следующим сообщением об ошибке:

1
2
3
4
5
6
Traceback (most recent call last):
  File «addNumber.py», line 4, in <module>
    addNumbers(», 10)
  File «addNumber.py», line 2, in addNumbers
    print a + b
TypeError: cannot concatenate ‘str’ and ‘int’ objects

Мы можем решить вышеуказанную проблему, проверив, являются ли переданные параметры целыми. Но это не решит проблему. Что если код сломается по какой-то другой причине и приведет к сбою программы? Работа с программой, которая дает сбой при обнаружении ошибки, не является хорошим зрением. Даже если обнаружена неизвестная ошибка, код должен быть достаточно надежным, чтобы корректно обработать сбой и дать пользователю понять, что что-то не так.

В Python мы используем операторы try и exception для обработки исключений. Всякий раз, когда код выходит из строя, генерируется исключение без сбоя программы. Давайте изменим программу добавления номеров, включив в нее операторы try и except .

1
2
3
4
5
6
7
def addNumbers(a, b):
    try:
        return a + b
    except Exception as e:
        return ‘Error occurred : ‘ + str(e)
 
print addNumbers(», 10)

Python будет обрабатывать весь код внутри оператора try и except . При обнаружении ошибки управление передается блоку except , пропуская код между ними.

Как видно из вышеприведенного кода, мы переместили наш код в оператор try и except . Попробуйте запустить программу, и она должна выдать сообщение об ошибке вместо сбоя программы. Причина исключения также возвращается в виде сообщения об исключении.

Вышеуказанный метод обрабатывает неожиданные исключения. Давайте посмотрим, как обрабатывать ожидаемое исключение. Предположим, что мы пытаемся прочитать определенный файл с помощью нашей программы Python, но файл не существует. В этом случае мы обработаем исключение и дадим пользователю знать, что файл не существует, когда это происходит. Посмотрите на код чтения файла:

1
2
3
4
5
6
7
8
try:
    try:
        with open(‘fname’) as f:
            content = f.readlines()
    except IOError as e:
        print str(e)
except Exception as e:
    print str(e)

В приведенном выше коде мы обрабатывали чтение файла в обработчике исключений IOError. Если код не работает из-за недоступности файла fname , ошибка будет обработана в обработчике IOError . Подобно исключениям IOError , существует множество стандартных исключений, таких как Arithmetic , OverflowError и ImportError , чтобы назвать несколько.

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

1
2
3
4
5
6
try:
    with open(‘fname’) as f:
        content = f.readlines()
    printb
except (IOError,NameError) as e:
    print str(e)

Приведенный выше код NameError исключения NameError и NameError при выполнении программы.

Предположим, что мы используем определенные ресурсы в нашей программе Python. Во время выполнения программы произошла ошибка, и она была выполнена только наполовину. В этом случае ресурс будет излишне задержан. Мы можем очистить такие ресурсы, используя предложение finally . Посмотрите на приведенный ниже код:

1
2
3
4
5
6
7
8
try:
    filePointer = open(‘fname’,’r’)
    try:
        content = filePointer.readline()
    finally:
        filePointer.close()
except IOError as e:
    print str(e)

Если во время выполнения вышеуказанного кода возникает исключение при чтении файла, filePointer будет закрыт в блоке finally .

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
import logging
 
# initialize the log settings
logging.basicConfig(filename=’app.log’,level=logging.INFO)
 
try:
    logging.info(‘Trying to open the file’)
    filePointer = open(‘appFile’,’r’)
    try:
        logging.info(‘Trying to read the file content’)
        content = filePointer.readline()
    finally:
        filePointer.close()
except IOError as e:
    logging.error(‘Error occurred ‘ + str(e))

Как видно из приведенного выше кода, сначала нам нужно импортировать библиотеку Python для ведения журнала, а затем инициализировать средство ведения журнала с именем файла журнала и уровнем ведения журнала. Существует пять уровней ведения журнала: DEBUG, INFO, WARNING, ERROR и CRITICAL. Здесь мы установили уровень ведения журнала на INFO, следовательно, журналы INFO и выше будут регистрироваться.

В приведенном выше коде у нас был один программный файл, поэтому было проще выяснить, где произошла ошибка. Но что мы делаем, когда задействованы несколько программных файлов? В таком случае получение трассировки стека ошибки помогает найти источник ошибки. Трассировка стека исключения может быть зарегистрирована как показано:

01
02
03
04
05
06
07
08
09
10
11
12
13
import logging
 
# initialize the log settings
logging.basicConfig(filename = ‘app.log’, level = logging.INFO)
 
try:
    filePointer = open(‘appFile’,’r’)
    try:
        content = filePointer.readline()
    finally:
        filePointer.close()
except IOError as e:
    logging.exception(str(e))

Если вы попытаетесь запустить вышеуказанную программу, при возникновении исключения в файле журнала будет зарегистрирована следующая ошибка:

1
2
3
4
5
ERROR:root:[Errno 2] No such file or directory: ‘appFile’
Traceback (most recent call last):
  File «readFile.py», line 7, in <module>
    filePointer = open(‘appFile’,’r’)
IOError: [Errno 2] No such file or directory: ‘appFile’

В этом уроке мы увидели, как начать работу с ошибками в Python и использовать модуль регистрации для регистрации ошибок. Мы видели использование операторов try , except и finally , которые весьма полезны при работе с ошибками в Python. Для более подробной информации, я бы рекомендовал прочитать официальную документацию по ведению журнала . Также ознакомьтесь с документацией по обработке исключений в Python .

Дайте нам знать ваши мысли в комментариях ниже.