use 'with' to redirect stdout

Jean-Paul Calderone exarkun at divmod.com
Mon Feb 11 17:15:40 CET 2008


On Mon, 11 Feb 2008 10:37:18 -0500, Neal Becker <ndbecker2 at gmail.com> wrote:
>This will work for stdout:
>
>from __future__ import with_statement
>from contextlib import contextmanager
>import sys
>
>@contextmanager
>def redirect(newfile):
>    orig_stdout = sys.stdout
>    sys.stdout = newfile
>    yield
>    sys.stdout = orig_stdout
>
>if __name__ == "__main__":
>    with redirect (open('stdout', 'w')):
>        print "hello"
>
>    print "we're back"
>
>But now, a harder puzzle that I'm stumped on.  Rewrite the above so that it
>doesn't hardcode sys.stdout, ie:
>
>def redirect (newfile, oldfile=None)
>
>where default oldfile is sys.stdout.  This seems much trickier.

You just have to parameterize oldfile.  The simplest way is with an object
and an attribute name.

    @contextmanager
    def redirect(fileholder, filename, newfile):
        orig = getattr(fileholder, filename)
        setattr(fileholder, filename, newfile)
        yield
        setattr(fileholder, filename, orig)

    with redirect(sys, 'stdout', open('stdout', 'w')):
        ...

Note that this really has nothing to do with redirection specifically,
anymore.  It's a general monkey-patching context manager.

Jean-Paul



More information about the Python-list mailing list