4

Since I've learned of the pattern, I've been using

with open('myfile.txt','w') as myfile:
    with contextlib.redirect_stdout(myfile):
        # stuff
        print(...) # gets redirected to file

This lets me use the print syntax (which I prefer) to write to files and I can easily comment it out to print to screen for debug. However, by doing this, I am removing my ability to both write to file and to the screen, and possibly writing less clear code. Are there any other disadvantages I should know about, and is this a pattern I should be using?

Ben
  • 5,952
  • 4
  • 33
  • 44

2 Answers2

8

is this a pattern I should be using?

In this particular case, I do think your pattern is not idiomatic, and potentially confusing to the reader of your code. The builtin print (since this is a Python-3x question) already has a file keyword argument which will do exactly what redirect_stdout does in your example:

with open('myfile.txt', 'w') as myfile:
    print('foo', file=myfile)

and introducing redirect_stdout only makes your reader wonder why you don't use the builtin feature. (And personally, I find nested with ugly. \-separated with even more ugly.)

As for the ease of commenting out (and for printing to both stdout and a file), well you can have as many print calls as you like, and comment them out as you need

with open('myfile.txt', 'w') as myfile:
    print('foo')
    print('foo', file=myfile)

Are there any other disadvantages I should know about

Nothing definite I can think of, except that it may not be the best solution (as in this case).

EDIT:

From the doc:

Note that the global side effect on sys.stdout means that this context manager is not suitable for use in library code and most threaded applications. It also has no effect on the output of subprocesses.

gil
  • 2,086
  • 12
  • 13
  • I agree with your assessment here, but it does beg the question -- why have `contextlib.redirect_stdout` in the first place? And I think that the answer is so that you can send output of functions that you don't control whereever you want (think about `dis.dis` for example) – mgilson Feb 12 '16 at 19:42
  • @mgilson Maybe you need to teach me about the `dis.dis` example you had in mind. I'm not sure why we don't just use the `file` argument of that function. The reason I think `redirect_stdout` exists, though just my guess, is because not every API has a `file` option like `print` and `dis.dis`. – gil Feb 12 '16 at 19:58
  • Well, it appears I choose a poor example. [In python2.7, `dis.dis`](https://docs.python.org/2/library/dis.html#dis.dis) doesn't have a `file` argument and I didn't realize they added it sometime in python3.x (probably the same time they added `redirect_stdout` to `contextlib` :-P) – mgilson Feb 12 '16 at 20:07
  • @mgilson If the old `dis.dis` lacked the `file` argument (and my Python age isn't old enough to know that), then yeah, I agree that's a use case of `redirect_stdout`. There probably still exist APIs like that, and so `redirect_stdout` will be around for while. – gil Feb 12 '16 at 20:49
  • Many good points. I didn't consider the threaded implications. – Ben Feb 12 '16 at 21:55
0

This question, about how to do exactly what you've been doing has quite a few comments and answers about the drawbacks of redirecting stdout, especially this comment to one of the answers:

With disk caching performance of the original should be acceptable. This solution however has the drawback of ballooning the memory requirements if there were a lot of output. Though probably nothing to worry about here, it is generally a good idea to avoid this if possible. Same idea as using xrange (py3 range) instead of range, etc. – Gringo Suave

Community
  • 1
  • 1
DJGrandpaJ
  • 571
  • 3
  • 7
  • 20