-
I believe this has already been answered by other users before me, so I only add it for the sake of completeness: the
withstatement simplifies exception handling by encapsulating common preparation and cleanup tasks in so-called context managers. More details can be found in PEP 343. For instance, theopenstatement is a context manager in itself, which lets you open a file, keep it open as long as the execution is in the context of thewithstatement where you used it, and close it as soon as you leave the context, no matter whether you have left it because of an exception or during regular control flow. Thewithstatement can thus be used in ways similar to the RAII pattern in C++: some resource is acquired by thewithstatement and released when you leave thewithcontext. -
Some examples are: opening files using
with open(filename) as fp:, acquiring locks usingwith lock:(wherelockis an instance ofthreading.Lock). You can also construct your own context managers using thecontextmanagerdecorator fromcontextlib. For instance, I often use this when I have to change the current directory temporarily and then return to where I was:from contextlib import contextmanager import os @contextmanager def working_directory(path): current_dir = os.getcwd() os.chdir(path) try: yield finally: os.chdir(current_dir) with working_directory("data/stuff"): # do something within data/stuff # here I am back again in the original working directoryHere’s another example that temporarily redirects
sys.stdin,sys.stdoutandsys.stderrto some other file handle and restores them later:from contextlib import contextmanager import sys @contextmanager def redirected(**kwds): stream_names = ["stdin", "stdout", "stderr"] old_streams = {} try: for sname in stream_names: stream = kwds.get(sname, None) if stream is not None and stream != getattr(sys, sname): old_streams[sname] = getattr(sys, sname) setattr(sys, sname, stream) yield finally: for sname, stream in old_streams.iteritems(): setattr(sys, sname, stream) with redirected(stdout=open("/tmp/log.txt", "w")): # these print statements will go to /tmp/log.txt print "Test entry 1" print "Test entry 2" # back to the normal stdout print "Back to normal stdout again"And finally, another example that creates a temporary folder and cleans it up when leaving the context:
from tempfile import mkdtemp from shutil import rmtree @contextmanager def temporary_dir(*args, **kwds): name = mkdtemp(*args, **kwds) try: yield name finally: shutil.rmtree(name) with temporary_dir() as dirname: # do whatever you want