使用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标准库之外的存储库中安装任何模块/软件包。
我认为您正在寻找argparse。
检查https://docs.python.org/3/library/argparse.html#filetype-objects。
您可以在哪里这样做
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('infile', nargs='?', type=argparse.FileType('r'),
... default=sys.stdin)
>>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'),
... default=sys.stdout)
因此infile
和outfile
默认将支持stdin
和stdout
的读写流。
click
在图书馆文档网站上查看更多详细信息
https://click.palletsprojects.com/en/7.x/api/#click.Filehttps://click.palletsprojects.com/en/7.x/arguments/#file-arguments
文件参数
由于所有示例都已使用文件名,因此解释如何正确处理文件是有意义的。如果命令行工具以Unix方式处理文件,则它们会更有趣,这是将
-
作为引用stdin / stdout的特殊文件。Click通过click.File类型支持此功能,它可以为您智能处理文件。它还针对所有版本的Python正确处理Unicode和字节,因此您的脚本保持了可移植性。
我相信该库是最友好的“ BASH / DASH”功能。
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)