Однако, если он не может подключиться, то db
не будет существовать ниже, поэтому я установил db = None
выше. Однако является ли это хорошей практикой?
Нет, установка db = None
не рекомендуется. Есть две возможности: либо соединение с базой данных будет работать, либо нет.
Подключение к базе данных не работает:
Поскольку возникшее исключение было перехвачено и не было повторно возбуждено, вы продолжаете, пока не достигнете cursor = db.Cursor()
.
db == None
, поэтому будет возбуждено исключение, похожее на TypeError: 'NoneType' object has no attribute 'Cursor'
. Поскольку исключение, сгенерированное при сбое подключения к базе данных, уже было перехвачено, причина сбоя скрыта.
Лично я всегда вызывал исключение соединения, если только вы не собираетесь повторить попытку в ближайшее время. Как вы поймаете это, зависит от вас; если ошибка не устранена, я пишу по электронной почте, чтобы сказать «иди и проверь базу данных».
Подключение к базе данных работает:
Переменная db
назначается в вашем блоке try:... except
. Если метод connect
работает, то db
заменяется объектом подключения.
В любом случае начальное значение db
никогда не используется.
Однако я слышал, что использование обработки исключений для управления потоком, подобное этому, является плохой практикой.
В отличие от других языков Python действительно использует обработку исключений для управления потоком. В конце своего ответа я дал ссылку на несколько вопросов о переполнении стека и программистах, которые задают аналогичный вопрос. В каждом примере вы увидите слова «но в Python».
Это не означает, что вы должны перебарщивать, но Python обычно использует мантру EAFP, " Легче попросить прощения, чем разрешения." Три наиболее популярных примера в Как мне проверить, существует ли переменная? являются хорошими примерами того, как вы можете использовать управление потоком или нет.
Является ли вложение исключений хорошей идеей? Или есть лучший способ справиться с такими зависимыми/каскадными исключениями?
Нет ничего плохого во вложенных исключениях, еще раз, пока вы делаете это разумно. Рассмотрите свой код. Вы можете удалить все исключения и обернуть все это в блок try:... except
. Если возникает исключение, вы знаете, что это было, но немного сложнее отследить, что именно пошло не так.
Что же тогда произойдет, если вы захотите сообщить по электронной почте о провале cursor.execute
? У вас должно быть исключение вокруг cursor.execute
, чтобы выполнить эту задачу. Затем вы повторно вызываете исключение, чтобы оно попало в ваш внешний try:...
. Отсутствие повторного повышения приведет к тому, что ваш код продолжит работу, как будто ничего не произошло, и любая логика, которую вы поместили во внешний try:...
для обработки исключения, будет проигнорирована.
В конечном итоге все исключения наследуются от BaseException
.
Кроме того, есть некоторые части (например, сбои соединения), где я бы хотел, чтобы скрипт просто завершился - отсюда и закомментированный вызов sys.exit().
Я добавил простой класс и как его вызвать, примерно так я бы сделал то, что вы пытаетесь сделать. Если это будет выполняться в фоновом режиме, то печать ошибок не имеет смысла — люди не будут сидеть и вручную искать ошибки. Они должны быть зарегистрированы любым вашим стандартным способом, и соответствующие люди должны быть уведомлены. По этой причине я удалил печать и заменил ее напоминанием о регистрации.
Поскольку я разделил класс на несколько функций, когда метод connect
дает сбой и возникает исключение, вызов execute
не будет выполняться, и сценарий завершится после попытки отключения.
import cx_Oracle
class Oracle(object):
def connect(self, username, password, hostname, port, servicename):
""" Connect to the database. """
try:
self.db = cx_Oracle.connect(username, password
, hostname + ':' + port + '/' + servicename)
except cx_Oracle.DatabaseError as e:
# Log error as appropriate
raise
# If the database connection succeeded create the cursor
# we-re going to use.
self.cursor = self.db.cursor()
def disconnect(self):
"""
Disconnect from the database. If this fails, for instance
if the connection instance doesn't exist, ignore the exception.
"""
try:
self.cursor.close()
self.db.close()
except cx_Oracle.DatabaseError:
pass
def execute(self, sql, bindvars=None, commit=False):
"""
Execute whatever SQL statements are passed to the method;
commit if specified. Do not specify fetchall() in here as
the SQL statement may not be a select.
bindvars is a dictionary of variables you pass to execute.
"""
try:
self.cursor.execute(sql, bindvars)
except cx_Oracle.DatabaseError as e:
# Log error as appropriate
raise
# Only commit if it-s necessary.
if commit:
self.db.commit()
Затем назовите это:
if __name__ == "__main__":
oracle = Oracle.connect('username', 'password', 'hostname'
, 'port', 'servicename')
try:
# No commit as you don-t need to commit DDL.
oracle.execute('ddl_statements')
# Ensure that we always disconnect from the database to avoid
# ORA-00018: Maximum number of sessions exceeded.
finally:
oracle.disconnect()
Дальнейшее чтение:
cx_Oracle
документация
Почему бы не использовать исключения в качестве обычного потока управления?
Является ли обработка исключений python более эффективнее, чем PHP и/или другие языки?
Аргументы за или против использования try catch в качестве логических операторов
person
Ben
schedule
24.03.2012