python 'with' statement, should I use contextlib.closing?

contextmanager, python, with-statement

Solution

Yes, you should be using `context.closing()`; your own version does something different entirely.

The `with` statement lets a context manager know when a block of code is entered and exited; on exit the context manager is also given access to the exception, if one occurred. File objects use this to automatically close the file when the block is exited.

The `connect_db()` function from the tutorial returns a `sqlite3` connection object, which can indeed be used as a context manager. However, the `connection.__exit__()` method doesn't close the connection, it commits the transaction on a successful completion, or aborts it when there is an exception.

The `contextlib.closing()` context manager on the other hand, calls the `connection.close()` method on the connection. This is something entirely different.

So, your second snippet may work, but does something different. The tutorial code closes the connection, your version commits a transaction. You are already calling `db.commit()`, so the action is actually redundant provided no exceptions are raised.

You could use the connection as a context manager again to have the automatic transaction handling behaviour:

def init_db():
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql') as f, db:
            db.cursor().executescript(f.read())

Note the `, db` on the second `with` line, ensuring that the `db.__exit__()` method is called when the block exits.

Problem

This is from flask tutorial Step 3: ``` from contextlib import closing def init_db(): with closing(connect_db()) as db: with app.open_resource('schema.sql') as f: db.cursor().executescript(f.read()) db.commit() ``` Regarding line 4, must I import and call 'contextlib.closing()'? When I've learned about with statement, many articles said that it closes file automatically after process like below. (same as Finally: `thing.close()`) ``` with open('filename','w') as f: f.write(someString); ``` Even though I don't use that `contextlib.closing()` like below, what's the difference? It's from version 2.7.6, Thank you. ``` def init_db(): with connect_db() as db: with app.open_resource('schema.sql') as f: db.cursor().executescript(f.read()) db.commit() ```

Original source