Sam
Sam

Reputation:

Python Beginner: How to Prevent 'finally' from executing?

The function code:

# 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()

I understand that in a try .. except .. finally, the finally block will always execute. In the above code, I don't want the finally in the second try block to execute if there is an exception in the first try block. What am I doing wrong?

(Note: Using python 2.4)

Clarification: I am not aware if MySQLdb closes connections automatically when an error occurs. The problem I am facing with the above code is, when there is an error in establishing a connection (the first try block of the code), calling dbi.close() in the finally block raises "AttributeError: 'NoneType' object has no attribute 'close'" with reference to dbi ...

Solution: This worked as desired -

# define at the start 
dbi = None
sql = None

In the finally block,

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

Thanks to those who replied. I learned something new from all of you. (I'll try to phrase my questions more clearly the next time :).

Upvotes: 3

Views: 2054

Answers (3)

Waylon Flinn
Waylon Flinn

Reputation: 20257

Don't use finally. If you don't want the code to always be executed then you should find another flow control structure that meets your needs.

One way to accomplish this behavior is to move the statements in your 'finally' block to the bottom of your 'try' block. That way they won't get executed when an exception is thrown but will get executed, after all other statements, otherwise.

EDIT:

After further discussion it appears that in your case you do actually want to use 'finally'. What I recommend is checking to see if your connection has already been closed before you attempt to close it.

Upvotes: 4

dbr
dbr

Reputation: 169593

Use else: instead of finally:. See the Exception Handling part of the docs:

The try ... except statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception.

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()

..basically:

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]

Upvotes: 6

duffymo
duffymo

Reputation: 308848

I think in this case you do want to use finally, because you want to close those connections.

I disagree with the notion that you should have two try blocks in the same method.

I think the flaw in the design is acquiring the connection and performing the query in the same method. I would recommend separating the two. A service class or method knows about the unit of work. It should acquire the connection, pass it to another class that performs the query, and closes the connection when it's done. That way the query method can throw any exception it encounters and leave the cleanup to the class or method that's responsible for the connection.

Upvotes: 5

Related Questions