0

I would like the following basic construct:

if fname:
    fhandle=open(fname,"w")
else:
    fhandle=sys.stdout

...code using fhandle for output....

Normally, I would open the file using "with" like this:

with open(name,"w") as fhandle:
      .... code using handle for output....

Is there a way to blend these two constructs, so that I can pass something to the open function in the with construct that will make fhandle point to sys.stdout? Or, if this is a dumb idea, what's the pythonic way to do this?

3 Answers3

1

I think, all you need is ternary operator:

with open('moo.txt', 'w') if YOU_CONDITION else sys.stdout as f:
    f.write('hello')

>> hello
Community
  • 1
  • 1
shybovycha
  • 9,794
  • 6
  • 47
  • 77
0

You could do something like this:

import sys
from contextlib import contextmanager

@contextmanager
def func(fname):
    fhandle = open(fname,"w") if fname else sys.stdout
    yield fhandle
    if fname:
        fhandle.close()

And use it like this:

with func(fname) as fhandle:
    ... your code ...
martineau
  • 99,260
  • 22
  • 139
  • 249
  • @MartijnPieters, the issue is: what happens on `stdout.__exit__`? is it in general a good idea? – bgusach Mar 30 '15 at 15:12
  • @ikaros45: it is just a file object, so it'll be closed. If you don't plan to write to it for the rest of the program runtime, then that's fine. – Martijn Pieters Mar 30 '15 at 15:13
  • @MartijnPieters, that is quite an assumption... I did think of this solution, but returning either a file, or a context manager that does not do anything on `__exit__`. – bgusach Mar 30 '15 at 15:15
  • @ikaros45: well, if you are using this at the top level where exiting the `with` statement means exiting the script, and errors go to `sys.stderr` instead, it is fine to close `sys.stdout`. Hence my request for clarification on the question. – Martijn Pieters Mar 30 '15 at 15:18
  • Yes, under these circumstances, that is perfectly fine. I wouldn't do it that way however, I prefer to forget about and specific situations. As the code grows, you're lost if you have to bear in mind specifics. – bgusach Mar 30 '15 at 15:20
  • FWIW, my revised answer doesn't close the file if it was set to `sys.stdout`. – martineau Mar 30 '15 at 15:23
  • I'm going to accept this answer because it's what I thought I wanted when I asked; but since I really don't want to close stdout, in the end I'm taking a completely different approach. Thanks all. – Jeremy Teitelbaum Mar 30 '15 at 15:27
  • @Jeremy: Thanks, but note, it won't close `stdout` on you. – martineau Mar 30 '15 at 15:30
  • @JeremyTeitelbaum out of interest, in what direction are you taking it? – NDevox Mar 30 '15 at 15:57
0

Put the code to handle output in a function.

def handle_output(fhandle):
    # do stuff

if fname:
    with open(fname,"w") as fhandle:
        handle_output(fhandle)
else:
    fhandle=sys.stdout
    handle_output(fhandle)

Feedback is always welcome on downvotes!

NDevox
  • 3,751
  • 4
  • 18
  • 32
  • I find it bizarre anyone downvoted you. I upvoted because this is the pattern I use, and it seems best to me. – ArtOfWarfare Mar 30 '15 at 15:15
  • @ArtOfWarfare thanks. I agree, I find the idea of closing stdout bizarre. I understand that it may not necessarily be harmful, but it's not necessary in the first place. – NDevox Mar 30 '15 at 15:17
  • I did not downvote, but I find this code clunky. I would create a function that returns an object with the context manager protocol (either a file handle, or a wrapper around stdout). Polymorphic and nice. – bgusach Mar 30 '15 at 15:17
  • @Ikaros45, I haven't used context managers (haven't had the need to) to differentiate in this way. What's the advantage over the above? The function should give the flexibility to use anything with a write method, is simple to make and is easy to understand. – NDevox Mar 30 '15 at 15:25
  • 1
    It is a subtle thing, but in the scope of such a function, I am thinking about writing some business info somewhere, and if possible, I would like not to think about where or how it happens (ie, it should be abstracted away). Moreover, passing arguments to be mutated is something I like to avoid (although a file is a perfectly fine usage) – bgusach Mar 30 '15 at 15:36
  • Of all the answers here, yours is the only one to gain any upvotes, so you can take solace in that... – ArtOfWarfare Mar 30 '15 at 15:56
  • Hah, thanks. I feel appreciated. – NDevox Mar 30 '15 at 15:57