Поймать python DatabaseErrors в целом

У меня есть схема базы данных, которая может быть реализована в различных механизмах баз данных (скажем, база данных MS Access, к которой я подключусь с помощью pyodbc, или база данных SQLite, к которой я подключусь через встроенный модуль sqlite3 в качестве простой пример).

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

def createConnection(connType, params):
    if connType == 'sqlite':
        return sqlite3.connect(params['filename'])
    elif connType == 'msaccess':
        return pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ={};'.format(params['filename']))
    else:
        # do something else

Теперь у меня есть код запроса, который должен работать с любым типом соединения (поскольку схема идентична независимо от базового механизма БД), но может вызвать исключение, которое мне нужно будет перехватить:

db = createDatabase(params['dbType'], params)

cursor = db.cursor()

try:
    cursor.execute('SELECT A, B, C FROM TABLE')
    for row in cursor:
        print('{},{},{}'.format(row.A, row.B, row.C))

except DatabaseError as err:
    # Do something...

Проблема, с которой я столкнулся, заключается в том, что классы DatabaseError из каждой реализации DB API 2.0 не имеют общего базового класса (кроме слишком общего исключения), поэтому я не знаю, как в общем случае отлавливать эти исключения. Очевидно, я мог бы сделать что-то вроде следующего:

try:
    # as before
except sqlite3.DatabaseError as err:
    # do something
except pyodbc.DatabaseError as err:
    # do something again

... где я включил явный блок catch для каждого возможного движка базы данных. Но мне это кажется явно непифоническим.

Как я могу в общем перехватить DatabaseErrors из различных базовых реализаций базы данных DB API 2.0?


person Drew Hall    schedule 22.10.2016    source источник


Ответы (1)


Есть несколько подходов:

  1. Используйте универсальное исключение, а затем определите, что это за исключение. Если его нет в вашем списке, вызовите исключение снова (или свое собственное). См .: Python Когда я перехватываю исключение, как мне узнать тип, файл и номер строки?

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

  3. На мой взгляд, более простой подход (и тот, который я использую на практике) состоит в том, чтобы иметь класс для всех соединений с базой данных и создавать подклассы для каждого конкретного типа / синтаксиса базы данных. Наследование позволяет позаботиться обо всех особенностях. По какой-то причине мне никогда не приходилось беспокоиться об этой проблеме.

person fralau    schedule 22.10.2016
comment
Ваше решение №2 помогло. Мне и в голову не приходило, что заявления except были динамичными. Итак, теперь я возвращаю из фабричной функции как класс исключений, так и специфичный для соединения, и проверяю возвращаемый тип исключения в операторе except. Работает как шарм! - person Drew Hall; 26.10.2016
comment
Забавно, я не имел в виду этого: я имел в виду, что вы можете перехватить исключение в своей фабричной функции и немедленно вызвать собственное стандартизованное исключение (используя строковое описание этого первого исключения). Но если ваше решение сработало, это тоже хорошо! - person fralau; 12.11.2019