Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 8, 2009 00:06:30

ozssss
От:
Зарегистрирован: 2009-08-07
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Вопрос по использованию исключений try … except (философский)

Писать на 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. прошу прощение за возможные орфогафические ошибки

Линк в тему (хоть он и о С++)



Офлайн

#2 Авг. 8, 2009 00:39:25

ZZZ
От: Москва
Зарегистрирован: 2008-04-03
Сообщения: 2161
Репутация: +  26  -
Профиль   Адрес электронной почты  

Вопрос по использованию исключений try … except (философский)

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

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... Но тут можно оленя поймать, однако...'



Офлайн

#3 Авг. 8, 2009 08:26:08

ozssss
От:
Зарегистрирован: 2009-08-07
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Вопрос по использованию исключений try … except (философский)

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 как вариант)



Офлайн

#4 Авг. 8, 2009 10:21:21

lightcaster
От:
Зарегистрирован: 2008-07-01
Сообщения: 31
Репутация: +  0  -
Профиль   Отправить e-mail  

Вопрос по использованию исключений try … except (философский)

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

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



Отредактировано (Авг. 8, 2009 10:25:17)

Офлайн

#5 Авг. 8, 2009 14:47:58

ZZZ
От: Москва
Зарегистрирован: 2008-04-03
Сообщения: 2161
Репутация: +  26  -
Профиль   Адрес электронной почты  

Вопрос по использованию исключений try … except (философский)

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'''Какой-то странный запрос, однако... Не работает и ругается страшно...''')
Это зависит от архитектуры программы. Вот этот пример более общий. Делай так, как нравится. :-)



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version