Однако, если он не может подключиться, то 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 в качестве логических операторов