使用Python的'with'语句和sys.stdout

15

我总是使用with语句打开和写入文件:

with open('file_path', 'w') as handle:
    print >>handle, my_stuff

然而,有一种情况下我需要更灵活,如果提供了sys.stdout(或其他类型的流),我需要能够写入它,而不是文件路径:

因此,我的问题是:是否有一种方法可以同时将with语句用于实际文件和sys.stdout

请注意,我可以使用以下代码,但我认为这违反了使用with的目的:

if file_path != None:
    outputHandle = open(file_path, 'w')
else:
    outputHandle = sys.stdout

with outputHandle as handle:
    print >>handle, my_stuff
4个回答

14

你可以创建一个上下文管理器,像这样使用它

import contextlib, sys

@contextlib.contextmanager
def file_writer(file_name = None):
    # Create writer object based on file_name
    writer = open(file_name, "w") if file_name is not None else sys.stdout
    # yield the writer object for the actual use
    yield writer
    # If it is file, then close the writer object
    if file_name != None: writer.close()

with file_writer("Output.txt") as output:
    print >>output, "Welcome"

with file_writer() as output:
    print >>output, "Welcome"

如果您没有向 file_writer 提供任何输入,它将使用 sys.stdout


2
我会用“is not”替换“!=”。 - Blender
@Blender 我在考虑交换 ifelse 部分,然后只需使用 if file_name :) 无论如何,我用 is not 解决了它 :) - thefourtheye
这篇文章值得更多的点赞!它为我提供了很好的起点,上下文管理器方法非常不显眼。 - Zombro
我认为应该是 writer = open(file_name, "w") 而不是 writer = open("Output.txt", "w"),但回答很好! - GermanK

4

事实上,对于stdout,您不需要使用上下文处理器,因为您不会打开或关闭它。更简单的抽象方式是:

def do_stuff(file):
    # Your real code goes here. It works both with files or stdout
    return file.readline()

def do_to_stdout():
    return do_stuff(sys.stdout)

def do_to_file(filename):
    with open(filename) as f:
        return do_stuff(f)


print do_to_file(filename) if filename else do_to_stdout()

3

使用Python3,可选的closefd参数被识别。 如果设置为False,则结果IO对象不会关闭底层fd:

if file_path != None:
    outputHandle = open(file_path, 'w')
else:
    outputHandle = open(sys.stdout.fileno(), 'w', closefd=False)

with outputHandle as handle:
    print(my_stuff, file=handle)

1
最简单的方法是直接使用“老派”的流式文件名,这样你的代码就不必更改。在Unix中,这是“/dev/tty”,在Windows中,这是“con”(尽管两个平台都有其他选择)。
if default_filename is None:
    default_filename = "/dev/tty"

with open(default_filename, 'w') as handle:
    handle.write("%s\n" % my_stuff)

这段代码已在Python 2.7.3和3.3.5中测试通过


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接