【问题标题】:How to abstract stdin/stdout and files?如何抽象标准输入/标准输出和文件?
【发布时间】:2018-04-01 00:52:36
【问题描述】:

我正在尝试编写一个 Python 脚本,它允许用户在标准输入/标准输出和输入/输出文件之间切换。但我不确定我的实现是否正确:

#!/usr/bin/python3

import fileinput
import sys

from contextlib import contextmanager
from contextlib import redirect_stdout


def foo(file):
    return ''.join([line for line in file])


@contextmanager
def run(input_file, output_file):
    stdin = '-' if input_file is None else input_file
    stdout = sys.stdout if output_file is None else open(output_file, 'w')
    with fileinput.input(stdin) as stdin, stdout:
        with redirect_stdout(stdout):
            print(foo(stdin))
  1. 代码管理资源是否正确?
  2. 如何正确处理字符编码?我希望所有内容都使用 utf-8。
  3. 上面的代码还有改进的余地吗?

【问题讨论】:

    标签: python python-3.x io character-encoding


    【解决方案1】:

    我认为您需要这样做。您不需要将run() 本身设为@contextmanager — 它只需使用一个(或多个,fileinput.inputredirect_stdout 都已经是一个)。我不确定您为什么使用fileinput.input,因为似乎只涉及一个输入文件。

    from contextlib import redirect_stdout
    import fileinput
    import sys
    
    def foo(file):
        return ''.join([line for line in file])
    
    def run(input_file, output_file):
        stdin = '-' if input_file is None else input_file
        stdout = sys.stdout if output_file is None else open(output_file, 'w')
        with fileinput.input(stdin) as stdin, redirect_stdout(stdout):
            print(foo(stdin))
    
    run('input.txt', 'output.txt')
    run('input.txt', None)
    

    【讨论】:

    • 感谢您的信息。我使用fileinput 因为可能有多个输入文件。主要目标是使脚本可以管道化。我不确定我是否理解您对@contextmanager 的评论。你是说在当前的实现中我不需要@contextmanager?另外,请您评论一下字符编码吗?
    • 我的意思是,既然fileinput.input()redirect_stdout() 都已经是上下文管理器,那么您也不需要将run() 也设置为一个。至于编码,如果stdout 没有被重定向,您可能会遇到问题,具体取决于您的操作系统的sys.stdout 的默认编码是什么。对于文件,您可能必须使用codecs.open() 来避免在从/向它们读取数据时出现编码问题,具体取决于它们包含的内容。与其在这里提出假设性问题,不如试着运行一下看看。
    最近更新 更多