Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

This is from flask tutorial Step 3(http://flask.pocoo.org/docs/tutorial/dbinit/#tutorial-dbinit). And I'm little curious about the line 4 of that.

Must I import and use that 'contextlib.closing()' method?

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 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() 
like image 666
su79eu7k Avatar asked Dec 27 '13 00:12

su79eu7k


People also ask

What is Contextlib closing?

contextlib. closing (thing) Return a context manager that closes thing upon completion of the block. This is basically equivalent to: from contextlib import contextmanager @contextmanager def closing(thing): try: yield thing finally: thing.

Why you should use context managers in Python?

Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement. Suppose you have two related operations which you'd like to execute as a pair, with a block of code in between.

What does the context manger do when you are opening a file using with?

A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. The code above will open the file and will keep it open until we are out of the with statement.

What does __ enter __ do in Python?

__enter__ and [__exit__] both are methods that are invoked on entry to and exit from the body of "the with statement" (PEP 343) and implementation of both is called context manager. the with statement is intend to hiding flow control of try finally clause and make the code inscrutable.


2 Answers

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.

like image 96
Martijn Pieters Avatar answered Sep 19 '22 23:09

Martijn Pieters


The only thing done by the with statement is to call __enter__ method before entering its block and __exit__ method before exiting it. If those methods are not defined the with statement won't work as you may expect. I don't know what is the return type of connect_db, but I guess that it could be many different things from different third-party libraries. So, your code without closing will probably work in many (all?) cases, but you never know what can be returned by connect_db.

like image 21
smeso Avatar answered Sep 22 '22 23:09

smeso