首页 > 解决方案 > 如何在不编写额外代码的情况下使用 Python 将“-”(破折号)读取为标准输入?

问题描述

使用 Python 3.5.x,没有比这更高的版本。

https://stackoverflow.com/a/30254551/257924是正确答案,但没有提供内置于 Python 中的解决方案,但需要从头开始编写代码:

我需要一个值为“-”的字符串来表示标准输入,或者它的值是我要读取的文本文件的路径。我想使用with操作符来打开这些文件中的任何一种,而不是使用条件逻辑来检查我的脚本中的“-”。我有一些有用的东西,但它似乎应该是内置在 Python 核心中的东西,并且不需要我滚动自己的上下文管理器,如下所示:

from contextlib import contextmanager

@contextmanager
def read_text_file_or_stdin(path):
    """Return a file object from stdin if path is '-', else read from path as a text file."""
    if path == '-':
        with open(0) as f:
            yield f
    else:
        with open(path, 'r') as f:
            yield f


# path = '-'  # Means read from stdin
path = '/tmp/paths'  # Means read from a text file given by this value
with read_text_file_or_stdin(path) as g:
    paths = [path for path in g.read().split('\n') if path]

print("paths", paths)

我计划通过类似于-p -“从标准输入读取”或-p some_text_file“从 some_text_file 读取”的意思将参数传递给脚本。

这是否需要我执行上述操作,还是 Python 3.5.x 中内置的东西已经提供了这个功能?这似乎是编写 CLI 实用程序的常见需求,它可能已经由 Python 核心或标准库中的某些东西处理。

我不想在 3.5.x 中的 Python 标准库之外的存储库中安装任何模块/包,只是为了这个。

标签: pythonstdincontextmanager

解决方案


argparse模块提供了一个FileType了解-约定的工厂。

import argparse

p = argparse.ArgumentParser()

p.add_argument("-p", type=argparse.FileType("r"))

args = p.parse_args()

请注意,这args.p是一个打开的文件句柄,因此无需“再次”打开它。虽然您仍然可以将它与with语句一起使用:

with args.p:
    for line in args.p:
        ...

这只确保在with语句本身发生错误时关闭文件。此外,您可能不想使用with,因为这将关闭文件,即使您打算稍后再次使用它。

您可能应该使用该atexit模块来确保文件在程序结束时关闭,因为它已经在开始时为您打开了。

import atexit

...

args = p.parse_args()
atexit.register(args.p.close)

推荐阅读