在Python中使用'with'语句和sys.stdout

15 投票
4 回答
5701 浏览
提问于 2025-04-17 21:23

我总是使用 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 个回答

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版本中测试的。

3

在Python 3中,有一个可选的参数叫做closefd。如果把它设置为False,那么生成的输入输出对象在关闭的时候不会关闭底层的文件描述符(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)
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()
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,也就是输出到屏幕上。

撰写回答