Python Beginner: как предотвратить выполнение команды finally? - PullRequest
3 голосов
/ 18 апреля 2009

Код функции:

# Connect to the DB
try:
    dbi = MySQLdb.connect(host='localhost', \
                          user='user', \
                          passwd='pass', \
                          db='dbname', \
                          port=3309)

    print "Connected to DB ..."

except MySQLdb.Error, e:
    apiErr = 2
    apiErrMsg = "Error %d: %s" % (e.args[0], e.args[1])
    return

    # To prevent try..finally bug in python2.4,
    # one has to nest the "try: except:" part. 
try:
    try:
        sql = dbi.cursor()
        sql.execute("""
        SELECT *
        FROM table
        WHERE idClient =  %s
        """, (key, ))

        access = sql.fetchall()

        # [some more code here]           

    except MySQLdb.Error, e:
        apiErr = 2
        apiErrMsg = "Error %d: %s" % (e.args[0], e.args[1])
        return

finally:
    sql.close()
    dbi.close()

Я понимаю, что при попытке .. кроме ... наконец, блок finally всегда будет выполняться. В приведенном выше коде я не хочу, чтобы finally во втором блоке try выполнялось, если в первом блоке try есть исключение. Что я делаю не так?

(Примечание: использование python 2.4)

Пояснение: я не знаю, если MySQLdb автоматически закрывает соединения при возникновении ошибки. Проблема, с которой я сталкиваюсь в приведенном выше коде, заключается в том, что при возникновении ошибки при установлении соединения (первый блок try кода) при вызове dbi.close () в блоке finally возникает ошибка «AttributeError: объект NoneType не имеет атрибут 'close' 'со ссылкой на dbi ...

Решение : Это сработало как хотелось -

# define at the start 
dbi = None
sql = None

В блоке finally,

if sql is not None:
    sql.close()
if dbi is not None:
    dbi.close()

Спасибо тем, кто ответил. Я узнал что-то новое от всех вас. (Я постараюсь сформулировать мои вопросы более четко в следующий раз:).

Ответы [ 3 ]

6 голосов
/ 18 апреля 2009

Используйте else: вместо finally:. См. Обработка исключений часть документов:

Оператор try ... except имеет необязательное условие else, которое, если оно присутствует, должно следовать за всеми, кроме предложений. Это полезно для кода, который должен быть выполнен, если предложение try не вызывает исключение.

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

.. в основном:

try:
    [code that might error]
except IOError:
    [This code is only ran when IOError is raised]
else:
    [This code is only ran when NO exception is raised]
finally:
    [This code is always run, both if an exception is raised or not]
5 голосов
/ 18 апреля 2009

Я думаю, что в этом случае вы хотите использовать наконец, потому что вы хотите закрыть эти соединения.

Я не согласен с тем, что у вас должно быть два блока try в одном методе.

Я думаю, что недостатком дизайна является получение соединения и выполнение запроса тем же способом. Я бы порекомендовал разделить два. Сервисный класс или метод знают о единице работы. Он должен получить соединение, передать его другому классу, который выполняет запрос, и закроет соединение, когда это будет сделано. Таким образом, метод запроса может выдать любое исключение, с которым он сталкивается, и оставить очистку для класса или метода, отвечающего за соединение.

4 голосов
/ 18 апреля 2009

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

Один из способов реализовать это поведение - переместить операторы в вашем блоке finally в конец блока try. Таким образом, они не будут выполнены при возникновении исключения, но будут выполнены после всех других операторов, в противном случае.

EDIT:

После дальнейшего обсуждения выясняется, что в вашем случае вы действительно хотите использовать «наконец». Я рекомендую проверить, было ли ваше соединение уже закрыто, прежде чем пытаться его закрыть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...