using sqlite3 in python with "WITH" keyword
Question:
I was doing a tutorial and came across a way to handle connections with sqlite3,
Then I studied about the WITH keyword and found out that it is an alternative to try,except,finally way of doing things
It was said that in case of file-handling, ‘WITH’ automatically handles closing of files and I thought similar with the connection as said in zetcode tutorial:-
“With the with keyword, the Python interpreter automatically releases
the resources. It also provides error handling.” http://zetcode.com/db/sqlitepythontutorial/
so I thought it would be good to use this way of handling things, but I couldn’t figure out why both (inner scope and outer scope) statements work? shouldn’t the WITH release the connection?
import sqlite3
con = sqlite3.connect('test.db')
with con:
cur = con.cursor()
cur.execute('SELECT 1,SQLITE_VERSION()')
data = cur.fetchone()
print data
cur.execute('SELECT 2,SQLITE_VERSION()')
data = cur.fetchone()
print data
which outputs
(1, u'3.6.21')
(2, u'3.6.21')
I don’t know what exactly the WITH is doing here(or does in general), so, if you will please elaborate on the use of WITH over TRY CATCH in this context.
And should the connections be opened and closed on each query? (I am formulating queries inside a function which I call each time with an argument) Would it be a good practice?
Answers:
From the docs: http://docs.python.org/2/library/sqlite3.html#using-the-connection-as-a-context-manager
Connection objects can be used as context managers that automatically commit or rollback transactions. In the event of an exception, the transaction is rolled back; otherwise, the transaction is committed:
So, the context manager doesn’t release the connection, instead, it ensures that any transactions occurring on the connection are rolled back if any exception occurs, or committed otherwise… Useful for DELETE
, UPDATE
and INSERT
queries for instance.
In general, a context manager is free to do whatever its author wants it to do when used. Set/reset a certain system state, cleaning up resources after use, acquiring/releasing a lock, etc.
In particular, as Jon already writes, a database connection object creates a transaction when used as a context manager. If you want to auto-close the connection, you can do
with contextlib.closing(sqlite3.connect('test.db')) as con:
with con as cur:
cur.execute('SELECT 1,SQLITE_VERSION()')
data = cur.fetchone()
print data
with con as cur:
cur.execute('SELECT 2,SQLITE_VERSION()')
data = cur.fetchone()
print data
You could also write your own wrapper around sqlite3 to support with
:
class SQLite():
def __init__(self, file='sqlite.db'):
self.file=file
def __enter__(self):
self.conn = sqlite3.connect(self.file)
self.conn.row_factory = sqlite3.Row
return self.conn.cursor()
def __exit__(self, type, value, traceback):
self.conn.commit()
self.conn.close()
with SQLite('test.db') as cur:
print(cur.execute('select sqlite_version();').fetchall()[0][0])
https://docs.python.org/2.5/whatsnew/pep-343.html#SECTION000910000000000000000
I was doing a tutorial and came across a way to handle connections with sqlite3,
Then I studied about the WITH keyword and found out that it is an alternative to try,except,finally way of doing things
It was said that in case of file-handling, ‘WITH’ automatically handles closing of files and I thought similar with the connection as said in zetcode tutorial:-
“With the with keyword, the Python interpreter automatically releases
the resources. It also provides error handling.” http://zetcode.com/db/sqlitepythontutorial/
so I thought it would be good to use this way of handling things, but I couldn’t figure out why both (inner scope and outer scope) statements work? shouldn’t the WITH release the connection?
import sqlite3
con = sqlite3.connect('test.db')
with con:
cur = con.cursor()
cur.execute('SELECT 1,SQLITE_VERSION()')
data = cur.fetchone()
print data
cur.execute('SELECT 2,SQLITE_VERSION()')
data = cur.fetchone()
print data
which outputs
(1, u'3.6.21')
(2, u'3.6.21')
I don’t know what exactly the WITH is doing here(or does in general), so, if you will please elaborate on the use of WITH over TRY CATCH in this context.
And should the connections be opened and closed on each query? (I am formulating queries inside a function which I call each time with an argument) Would it be a good practice?
From the docs: http://docs.python.org/2/library/sqlite3.html#using-the-connection-as-a-context-manager
Connection objects can be used as context managers that automatically commit or rollback transactions. In the event of an exception, the transaction is rolled back; otherwise, the transaction is committed:
So, the context manager doesn’t release the connection, instead, it ensures that any transactions occurring on the connection are rolled back if any exception occurs, or committed otherwise… Useful for DELETE
, UPDATE
and INSERT
queries for instance.
In general, a context manager is free to do whatever its author wants it to do when used. Set/reset a certain system state, cleaning up resources after use, acquiring/releasing a lock, etc.
In particular, as Jon already writes, a database connection object creates a transaction when used as a context manager. If you want to auto-close the connection, you can do
with contextlib.closing(sqlite3.connect('test.db')) as con:
with con as cur:
cur.execute('SELECT 1,SQLITE_VERSION()')
data = cur.fetchone()
print data
with con as cur:
cur.execute('SELECT 2,SQLITE_VERSION()')
data = cur.fetchone()
print data
You could also write your own wrapper around sqlite3 to support with
:
class SQLite():
def __init__(self, file='sqlite.db'):
self.file=file
def __enter__(self):
self.conn = sqlite3.connect(self.file)
self.conn.row_factory = sqlite3.Row
return self.conn.cursor()
def __exit__(self, type, value, traceback):
self.conn.commit()
self.conn.close()
with SQLite('test.db') as cur:
print(cur.execute('select sqlite_version();').fetchall()[0][0])
https://docs.python.org/2.5/whatsnew/pep-343.html#SECTION000910000000000000000