Bug in Python 1.5.2 exception handling?

Dave Cole djc at itga.com.au
Wed Dec 15 18:42:14 EST 1999


Tim> [Dave Cole]
Tim> > It looks like function locals are not deleted if that function is
Tim> > terminated by an exception.
Tim> 
Tim> That's true, but it's not a bug: Python doesn't define the
Tim> lifetime of objects.  CPython is much more predictable than
Tim> JPython in this respect-- thanks to using refcounts --but you
Tim> still rely on it at your own risk.  In the case of a function
Tim> that terminates due to exception, the locals are still very much
Tim> alive, because they *can* be reached via the traceback object
Tim> (from which the chain of stack frames can be reached, from which
Tim> the locals can be reached).

Der...  I forgot about the traceback stuff.  I have even written some
code to give nice pretty HTML formatted tracebacks for the Python CGI
stuff I have written here.

A trap for young players if ever there was one.

Tim> Change your loop to:
Tim> 
Tim> for val in range(3):
Tim>     try:
Tim>         check_raise(val)
Tim>     except:
Tim>         try:
Tim>             raise "dummy"
Tim>         except:
Tim>             pass
Tim> 
Tim> and you'll see that the 'raise "dummy"' has the same effect.

And in doing so, you end up dropping all references to the previous
traceback.  Not really what I was after, but oh well.

The reason that I was worried about this was that I am doing some
database stuff using my Sybase module:

        plug:  http://www.itga.com.au/~djc/sybase.html

I wanted to automatically rollback a transaction when an exception was
raised during processing.  I made a class like this:

class Transaction:
    def __init__(self, db, name):
        self.db = db
        self.name = name
        self.db.execute('begin transaction %s' % (self.name,))
        self.commit = 0

    def __del__(self):
        if self.commit:
            self.db.execute('commit transaction %s' % (self.name,))
        else:
            self.db.execute('rollback transaction %s' % (self.name,))

Then I thought that all I would have to do was:

    def something_or_other(self):
        tran = Transaction(self.db, 'update_id')
        # lots o' database stuff
        tran.commit = 1

I suppose it will still work for the rollback case, but just not when
I expect it to.

Tim> > class c:
Tim> >     def __init__(self, val):
Tim> >         self.val = val
Tim> >     def __del__(self):
Tim> >         print val, 'deleted'
Tim> 
Tim> You really want
Tim> 
Tim>         print self.val, 'deleted'

I was really quite determined to confuse myself.

- Dave






More information about the Python-list mailing list