How to handle both `with open(…)` and `sys.stdout` nicely?

后端 未结 13 744
长发绾君心
长发绾君心 2020-12-07 14:47

Often I need to output data either to file or, if file is not specified, to stdout. I use the following snippet:

if target:
    with open(target, \'w\') as h         


        
相关标签:
13条回答
  • 2020-12-07 14:52

    How about opening a new fd for sys.stdout? This way you won't have any problems closing it:

    if not target:
        target = "/dev/stdout"
    with open(target, 'w') as f:
        f.write(content)
    
    0 讨论(0)
  • 2020-12-07 14:57
    if (out != sys.stdout):
        with open(out, 'wb') as f:
            f.write(data)
    else:
        out.write(data)
    

    Slight improvement in some cases.

    0 讨论(0)
  • 2020-12-07 14:58

    Another possible solution: do not try to avoid the context manager exit method, just duplicate stdout.

    with (os.fdopen(os.dup(sys.stdout.fileno()), 'w')
          if target == '-'
          else open(target, 'w')) as f:
          f.write("Foo")
    
    0 讨论(0)
  • 2020-12-07 14:59

    The following solution is not a beauty, but from a time long, long ago; just before with ...

    handler = open(path, mode = 'a') if path else sys.stdout
    try:
        print('stuff', file = handler)
        ... # other stuff or more writes/prints, etc.
    except Exception as e:
        if not (path is None): handler.close()
        raise e
    handler.close()
    
    0 讨论(0)
  • 2020-12-07 15:00

    Okay, if we are getting into one-liner wars, here's:

    (target and open(target, 'w') or sys.stdout).write(content)
    

    I like Jacob's original example as long as context is only written in one place. It would be a problem if you end up re-opening the file for many writes. I think I would just make the decision once at the top of the script and let the system close the file on exit:

    output = target and open(target, 'w') or sys.stdout
    ...
    output.write('thing one\n')
    ...
    output.write('thing two\n')
    

    You could include your own exit handler if you think its more tidy

    import atexit
    
    def cleanup_output():
        global output
        if output is not sys.stdout:
            output.close()
    
    atexit(cleanup_output)
    
    0 讨论(0)
  • 2020-12-07 15:02
    import contextlib
    import sys
    
    with contextlib.ExitStack() as stack:
        h = stack.enter_context(open(target, 'w')) if target else sys.stdout
        h.write(content)
    

    Just two extra lines if you're using Python 3.3 or higher: one line for the extra import and one line for the stack.enter_context.

    0 讨论(0)
提交回复
热议问题