Context Managers

The with statement

In [3]:
f = open("a.txt", "w")
f.write("hello")
f.close()
In [4]:
with open("a.txt", "w") as f:
    f.write("hello")
In [7]:
f = open("a.txt")
dir(f)
Out[7]:
['__class__',
 '__delattr__',
 '__doc__',
 '__enter__',
 '__exit__',
 '__format__',
 '__getattribute__',
 '__hash__',
 '__init__',
 '__iter__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'close',
 'closed',
 'encoding',
 'errors',
 'fileno',
 'flush',
 'isatty',
 'mode',
 'name',
 'newlines',
 'next',
 'read',
 'readinto',
 'readline',
 'readlines',
 'seek',
 'softspace',
 'tell',
 'truncate',
 'write',
 'writelines',
 'xreadlines']

Example: chdir

In [21]:
import os
class chdir:
    def __init__(self, dir):
        self.dir = dir
        print "__init__"
        
    def __enter__(self):
        print "__enter__"
        self.olddir = os.getcwd()
        os.chdir(self.dir)
        return self
        
    def __exit__(self, *a):
        print "__exit__"
        os.chdir(self.olddir)

print os.getcwd()
print "before with"
with chdir("/tmp") as x:
    print os.getcwd()
print "after with"
print os.getcwd()
/Users/anand/Dropbox/Trainings/2013/advancedpython-may2013
before with
__init__
__enter__
/private/tmp
__exit__
after with
/Users/anand/Dropbox/Trainings/2013/advancedpython-may2013

Problem Write a context manager capture_output to capture stdout inside a with block.

with capture_output() as buf:
    print "hello"

out = buf.getvalue()
print "captured", repr(out)

Hint: See StringIO.StringIO and sys.stdout.

Lets try to understand how to capture output without context managers.

In [8]:
import sys
from StringIO import StringIO

oldstdout = sys.stdout
buf = StringIO()
sys.stdout = buf
print "hello"
print "world"
sys.stdout = oldstdout
print "captured", repr(buf.getvalue())
captured 'hello\nworld\n'
In [6]:
# solution

from StringIO import StringIO
import sys

class capture_output:
    def __init__(self):
        self.buf = StringIO()

    def __enter__(self):
        self.oldstdout = sys.stdout
        sys.stdout = self.buf
        return self.buf
        
    def __exit__(self, type, exc, traceback):
        sys.stdout = self.oldstdout
    
#with capture_output() as buf:
#    print "hello"

capture_output()

print "hello"

#out = buf.getvalue()
#print "captured", repr(out)
hello

Example: ignore_exception

In [14]:
class ignore_exception:
    def __init__(self):
        pass

    def __enter__(self):
        pass
        
    def __exit__(self, type, exc, traceback):
        print type, exc, traceback
        return True

with ignore_exception():
    print "begin"
    raise IOError("fo")
    
    
begin
<type 'exceptions.IOError'> fo <traceback object at 0x102f48998>

Problem Improve the above ignore_exception class to ignore only one particular exception.

with ignore_exception(IOError):
    raise IOError("foo")
In [ ]: