【问题标题】:Argparse optional stdin argumentargparse 可选标准输入参数
【发布时间】:2013-11-26 19:20:55
【问题描述】:

我正在尝试指定一个采用标准输入的可选参数。这将主要用于我程序中的管道数据,所以someprog that outputs | python my_prog

我遵循了 argparse 文档,并在 Stackoverflow 上阅读了很多关于此的问题/答案,但似乎没有一个对我有用。

这是我最初拥有的:

parser = argparse.ArgumentParser(description='Upgrade Instance.')
parser.add_argument('--app', '-a', dest='app', action='store', required=True)
parser.add_argument('--version', '-v', dest='version', action='store', default='', required=False)
parser.add_argument('--config', '-c', dest='config', action='store', default = '', required=False)
args = parser.parse_args()

现在我想做的是允许用户使用管道传递version,而不是传递它。

我在顶部添加了parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin),但这使它成为一个位置参数。这怎么可能?我认为nargs=? 使它成为可选的。

我需要它是一个可选参数。所以我把它改成:

parser.add_argument('--infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)

这使它成为一个可选参数,但如果没有传递管道,程序会挂起等待 stdin 作为默认值。删除 default=sys.stdin 并将某些内容输入我的程序中:

close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

运行时。当我打印args 时,我得到:Namespace(app='app', config='', g=False, hosts='03.app', infile=None, version='')

看来我做的事情很简单,很普通,很多人问过。但它似乎对我不起作用。

关于如何让它工作的任何建议?

【问题讨论】:

  • 你的意思是你试图创建一个参数,让你的程序从标准输入读取数据?
  • 还有 - Python 2 或 3?
  • @RyPeck:Python 2.7。是的,一个将从标准输入中读取的参数。
  • 你能用一个你期望行为的例子来更新你的问题吗?
  • 这个问题可能更恰当地满足您的需求 - stackoverflow.com/questions/699390/…

标签: python arguments argparse


【解决方案1】:

这样做...没有指定参数。如果你将管道输入传递给它运行的程序,你不这样做,它仍然会运行。 raw_input() 也可以。

import sys

if not sys.stdin.isatty():
    stdin = sys.stdin.readlines()
    print stdin
    sys.stdin = open('/dev/tty')
else:
    print "No stdin"

test_raw = raw_input()
print test_raw

演示 -

rypeck$ echo "stdin input" | python test_argparse.py -a test 
['stdin input\n']
raw_input working!
raw_input working!
rypeck$ python test_argparse.py -a test
No stdin
raw_input working!
raw_input working!

【讨论】:

  • 当没有输入通过管道传输到我的程序时,这会挂起等待标准输入。
  • 好的。所以你希望能够指定一个选项,让程序从标准输入读取?
  • 是的。这有效,但不适用于 argparse。我的 argparse 管道损坏了
【解决方案2】:

我自己也在探讨这个问题,并发现这里的选项有一个小的改进——希望它能帮助未来的旅行者。如果您希望在提供标志时从标准输入中读取,目前还不是 100% 清楚,但似乎这可能是您的目标;我的回答是基于这个假设。我正在使用 3.4,以防万一这成为问题...

我可以声明一个可选参数,例如:

parser.add_argument("-v", "--version", nargs='?', const=sys.stdin, action=StreamType)

我没有指定默认值,因为它仅在选项完全不存在时使用,而 const 仅在标志存在但没有参数时使用。 StreamType 是我编写的一个很小的 ​​argparse.Action 子类,它只是尝试从标准输入流中读取一行,如果这不起作用,则只保存原始值:

class StreamType(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        try:
            setattr(namespace, self.dest, values.readline().strip())
        except AttributeError:
            setattr(namespace, self.dest, values)

这应该产生类似:

$ blah --version v1.1.1
Namespace(version='v1.1.1')

$ echo "v1.0.3" | blah --version
Namespace(version='v1.0.3')

【讨论】:

    【解决方案3】:

    你用args.infile做什么?因为你得到了一个命名空间,argparse 不是挂起或给出错误的部分。

    p = argparse.ArgumentParser()
    p.add_argument('--infile', type=argparse.FileType('r'),default='-')
    # p.add_argument('infile', nargs='?', type=argparse.FileType('r'),default='-') # positional version
    args = p.parse_args()
    print(args)
    print args.infile.read()
    -----------
    $ cat myprog.py | python myprog.py --infile -
    $ cat myprog.py | python myprog.py
    $ python myprog.py myprog.py  # with the positional version
    $ python myprog.py - < myprog.py  # with the positional version
    

    很好地呼应了代码。第二个调用也适用于“可选位置”。

    不幸的是,术语optional/positionaloptional/required 有重叠。

    如果位置参数(是的,“位置”的另一种用法)具有前缀字符,如 ---,则称为 optional。默认情况下,其required 参数为False,但您可以将其设置为True。但如果参数是'infile'(无前缀),则为positional,即使?optional(非必需)。

    顺便说一句,默认action'store',所以你不需要指定。你也不需要指定required,除非它是True

    使用FileType,指定stdin 的便捷方式是-

    不要将'?'--infile 一起使用,除非你真的想要None

    【讨论】:

    • 嗯,这很有趣,在最后添加 - 就可以了。这是为什么?此外,似乎在某些时候要求raw_input 不起作用。这是真的?如何解决这个问题?
    • 因为-相当于说“从STDIN读入”/要求用户输入。
    • 关于?--infile,那我用什么?
    猜你喜欢
    • 2016-01-14
    • 2011-11-26
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2017-11-28
    • 2019-11-17
    • 2021-01-07
    • 2014-04-15
    相关资源
    最近更新 更多