添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
爱喝酒的手电筒  ·  Add settings to ...·  2 月前    · 
热心的春卷  ·  HTL 概述 | Adobe ...·  2 月前    · 
不拘小节的排球  ·  cdbook网站 - 百度·  2 月前    · 
刚毅的硬币  ·  phpjavabridge/Java.inc ...·  5 月前    · 

今天在写 Python 单元测试的时候需要获取到待测试方法的 print() 输出,在 Shell 中使用管道重定向输出很容易,但是在 Python 中如何进行呢?

Python 中的标准输入输出

当我们在 Python 中打印值调用 print(value) 时候,等价于调用 sys.stdout.write(value+'\n')

print 将内容打印到了控制台,然后追加了一个换行符

input 和 sys.stdin

当我们用 raw_input(‘promption: ‘) 时,事实上是先把提示信息输出,然后捕获输入

以下两组在实际上等价:

1
2
3
4
5
hi=raw_input('Hi~')

sys.stdout.write('Hi~')
# -1 to discard the '\n' in input stream
hi=sys.stdin.readline()[:-1]

而在Python 3中新增的 input() 函数则在此基础上,增加了类型判断的处理,尝试将输入解析为适当的数据类型。

实际上 print 或者 raw_input 在 cpython 中的源码要复杂得多,这里‘等价’的仅是示意其与标准输入输出直接相关。源码可以参考文末给出的链接

输出重定向

默认的 sys.stdout 指向控制台,我们可以重定向到其他流(或者具有 write 方法的对象):

1
2
3
4
5
6
#标准输出重定向至文件
with open('out.txt', 'w+') as f:
sys.stdout = f

# 标准输出重定向至字符流
sys.stdout = strout = StringIO()

完成任务后最好恢复标准输出至原先的地址(默认控制台):

  • 可以在重定向前获取 stdout 的默认引用,恢复的时候再指向这个引用即可

    1
    2
    3
    4
    5
    6
    orig_stdout = sys.stdout
    # ...$重定向代码$...
    # ...print('hahaha...')...

    # 恢复
    sys.stdout = orig_stdout
  • 或使用 sys.__stdout__ ,其保存程序开始时 sys.stdout 的原始值,且不受重定向影响

    1
    2
    3
    # ...$重定向代码$...
    # ...print('hahaha...')...
    sys.stdout = sys.__stdout__
  • 结合上下文管理器,我们还可以这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @contextmanager
    def stdout_redirected(new_stdout):
    save_stdout = sys.stdout
    sys.stdout = new_stdout
    try:
    yield None
    finally:
    sys.stdout = save_stdout

    # 使用
    with opened(filename, "w") as f:
    with stdout_redirected(f):
    print "Hello world"

    应用示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import sys
    from io import StringIO

    # parse 函数直接将'解析'结果打印出来了,我们需要判断解析是否正确

    def parse(query):
    print(f'query: {query}')

    def test(query):
    sys.stdout = strdout = StringIO()
    parse(query)
    sys.stdout = sys.__stdout__
    return strdout.getvalue()

    result = test('This message is for query')
    print(result.split()[1])

    # output:This

    同样的, sys.stderr , sys.stdin 也都可以被重定向到多个地址。

    References