Найти - Пользователи
Полная версия: Вопрос по использованию исключений try … except (философский)
Начало » Python для новичков » Вопрос по использованию исключений try … except (философский)
1
ozssss
Писать на Python-e я уже научился а творить еще нет (((
Тут недавно на глаза попался код (немного упрощен ) :
import sys
import sqlite3

# Обертка для базы данных
class Database:
# Класс-обертка для соединения,
# чтобы использовать с with
class dbConnection:
def __init__(self, dbfile):
self.dbfile = dbfile
def __enter__(self):
self.connection = sqlite3.connect(self.dbfile)
self.connection.row_factory = sqlite3.Row
return self.connection
def __exit__(self, type, value, traceback):
if traceback is None:
self.connection.commit()
self.connection.close()
else:
self.connection.rollback()
self.connection.close()
self.connection = None

def __init__(self, dbfile='./users.db'):
# Создание таблицы при первом запуске
newdb = 1 if not os.path.isfile(dbfile) else 0
if newdb:
try:
with self.dbConnection(dbfile) as connection:
connection.execute("""CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
jid TEXT UNIQUE NOT NULL,
token TEXT NOT NULL,
shard TEXT NOT NULL
)""")
except:
raise DatabaseError

self.dbfile = dbfile


def user(self, jid):
try:
with self.dbConnection(self.dbfile) as connection:
res = connection.execute('SELECT * FROM `users` WHERE `jid`=?',
(jid,)).fetchone()
return res
except:
raise DatabaseError


def updateUser(self, jid, token="", shard=""):
try:
with self.dbConnection(self.dbfile) as connection:
connection.execute("""REPLACE INTO users
(jid, token, shard)
VALUES
(?, ?, ?)""",
(jid, token, shard))
except:
raise DatabaseError


def delUser(self, jid):
try:
with self.dbConnection(self.dbfile) as connection:
connection.execute("DELETE FROM `users` WHERE `jid` = ?",
(jid,))
except:
raise DatabaseError

langpack = {
' dbError ': "error DB"
}

storage = Database()

# Классы для исключений:
# raise BasicError - стандартное значение,
# raise BasicError('Error!') - заданное.
class BasicError(Exception):
default = ''
def __init__(self, value=None):
self.value = self.default if not value else value
def __str__(self):
return self.value
class DatabaseError(BasicError):
default = Database.langpack['dbError']
Этот код навел меня на мысль о целесообразности использования try … except.
Для чего возбуждать однотипные пользовательские исключение в этом примере, а главное зачем использовать try … except в блоках исключение в которых ведут к необратимому аварийному завершению программы? (если не брать в расчет необходимость вывода своего сообщения об ошибке)
Поясню :
Вот пример где try … except просто необходим
while 1:
try:
x = int(raw_input("Введите число ")) #Здесь может возникнуть исключение
break #Если всё правильно, то выходим из бесконечного while
except ValueError: #А вот здесь обрабатывается исключение неверного формата числа
print ''Ой-ой. Неправильное число. Попробуйте снова..."
а вот здесь :
try:
with self.dbConnection(dbfile) as connection:
connection.execute("""CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
jid TEXT UNIQUE NOT NULL,
token TEXT NOT NULL,
shard TEXT NOT NULL
)""")
except:
raise DatabaseError
сомневаюсь .

Может я что-то упускаю?
Кто что думает по поводу использования try … except , поделитесь соображениями.

P.S. прошу прощение за возможные орфогафические ошибки

Линк в тему (хоть он и о С++)
ZZZ
Во-первых, никогда не перехватывай все исключения скопом. Т.е. приведённый тобой код хоть и работает, но не корректен.
Во-вторых, обрати внимание на то, что райзится своё исключение. Оно вполне может перехватываться где-то уровнем выше. Там, где требуется перехватить только это исключение и никакое другое, вроде ошибки базы данных в запросе после создания. Как пример:
class DatabaseError(RuntimeError): pass

def init(self):
try:
with self.dbConnection(dbfile) as connection:
connection.execute("""CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
jid TEXT UNIQUE NOT NULL,
token TEXT NOT NULL,
shard TEXT NOT NULL
)""")
except sqlite3.DatabaseError as exc:
raise DatabaseError

try:
init(self)
with self.dbConnection(dbfile) as conn:
conn.execute(u'''Какой-то странный запрос, однако... Не работает и ругается страшно...''')
except DatabaseError:
print u'Однако Error... Но тут можно оленя поймать, однако...'
ozssss
ZZZ
Во-первых, никогда не перехватывай все исключения скопом. Т.е. приведённый тобой код хоть и работает, но не корректен.
Во-вторых, обрати внимание на то, что райзится своё исключение. Оно вполне может перехватываться где-то уровнем выше. Там, где требуется перехватить только это исключение и никакое другое, вроде ошибки базы данных в запросе после создания. Как пример:
А смысл ловить sqlite3.DatabaseError в __init__? Для этого примера обработка любого исключения (sqlite3.DatabaseError) в конструкторе будет выглядеть так:
Print “……. Error …….” 
os._exit(0)
а вот для conn.execute :
try:
init(self)
with self.dbConnection(dbfile) as conn:
conn.execute(u'''Какой-то странный запрос, однако... Не работает и ругается страшно...''')
except DatabaseError:
print u'Однако Error... Но тут можно оленя поймать, однако...'
Есть шанс, что смогу обработать исключение и не завершить программу (переформировать строку для conn.execute как вариант)
lightcaster
В любом случае ловить все исключения это ошибочное решение.
Что же касается, ловить или нет: обычно работает правило - обрабатывай исключение там, где ты можешь его обработать.
В данном же случае (__init__) можешь не перехватывать, если устроит просто падение со стандартным икспшном. Или обработай и аварийно завершись, если ничего не можешь сделать.

Если же отвечать на философский вопрос - зачем это делать вообще, то далеко не все приложения завершаются, не обнаружив БД. К примеру, некоторые могут вывести в гуй диалог и попросить пользователя скорректировать адрес/имя БДю
ZZZ
ozssss
А смысл ловить sqlite3.DatabaseError в __init__?
Чтобы сгенерировать своё исключение, Которое мы отлавливаем уровнем выше.
Приведённый мною код, просто пример. В нём мы отловим ошибку базы данных в init, но не поймаем в последующим запросе.
Ну да, можно было обернуть в try-except один init, перехватить sqlite3.DatabaseError и радоваться жизни. Возможно, это был бы более правильный подход. Что-то вроде так:
def init(self):
with self.dbConnection(dbfile) as connection:
connection.execute("""CREATE TABLE ...)""")

try:
init(self)
except sqlite3.DatabaseError:
print u'Однако Error... Но тут можно оленя поймать, однако...'
else:
with self.dbConnection(dbfile) as conn:
conn.execute(u'''Какой-то странный запрос, однако... Не работает и ругается страшно...''')
Это зависит от архитектуры программы. Вот этот пример более общий. Делай так, как нравится. :-)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB