views:

121

answers:

2

If I have the following code:

import sqlite
sqlite.connect('tmp.db').cursor().close()

I get the following error message:

Traceback (most recent call last):
  File "searchengine2.py", line 13, in ?
    sqlite.connect('tmp.db').cursor().close()
  File "/usr/lib64/python2.4/site-packages/sqlite/main.py", line 280, in close
    if self.con and self.con.closed:
ReferenceError: weakly-referenced object no longer exists

However, if I modify the code in the following way:

import sqlite
x1 = sqlite.connect('tmp.db')
x2 = x1.cursor()
x3 = x2.close()

everything is fine. Why?

+2  A: 

Apparently the cursor keeps a weak reference to the connection (self.con). Because you chain the functions, the connection you've instantiated is out of scope as soon as you instantiate the cursor -- nothing holds a strong reference to the connection anymore, and the connection is eligible for garbage collection.

Therefore, by the time you try to close the cursor (which in turn tries to close the connection), the connection is already out of scope and may have been garbage collected -- if it was, then the connection is already closed.

There's no way to get around this without modifying the cursor's source to make it hold a strong reference to the connection, and there's no easy way to tell how many problems that might introduce if you do it that way. (Good) designers don't arbitrarily make weak references without a good reason.

(Hopefully you understand weak references from your last question.)

Mark Rushakoff
@Mark, good diagnosis, but the choice to move to weak refs is well documented in the history of pysqlite release notes: very simply, cursors used to have strong references to connections, but that of course sometimes kept connections alive against programmers' wishes, so the decision was made to use weak refs instead -- no mystery here;-).
Alex Martelli
I didn't actually look up any hard data on why/whether weak references were used. Thanks for confirming my suspicions :)
Mark Rushakoff
+1  A: 

It looks like cursor() returns (and keeps) a weak reference to the connection, so that then, when the strong reference to your connection is off the call stack, your connection (the result of connect()) is left without any strong references. So by the time close() is called, your connection has been destructed.

The second form avoids this by keeping a strong reference to your connection around the whole time.

chaos