python argparse总是设置与可选参数相关的默认值

时间:2015-03-10 15:11:44

标签: python default argparse optional-parameters

我使用python 3,我想设置argparse总是设置相对于我选择的预定义可选参数的默认键。

E.g。我将一些输入文件传递给脚本。可选参数指定是否应由脚本旋转输入文件。我得到一个输入文件列表,但我还想要一个包含' True'的相同大小的列表。用户想要旋转输入文件的位置,或者当用户没有做出选择时默认为false

例如

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--input', action='append', required=True, help='Input pdf files.')
parser.add_argument('--rotate', action='store_true', default=False, help='Rotate the input file')
args = parser.parse_args()
print(args)

我用这个命令调用脚本:

python argparse_test.py --input 1.pdf --input 2.pdf --rotate

这是输出

  

命名空间(输入= [' 1.pdf',' 2.pdf'],rotate = True)

但我想要这个输出

  

命名空间(输入= [' 1.pdf',' 2.pdf'],rotate = [False,True])

请注意,--rotate可以是任何必须由我在--input之前写在--rotate文件上的python脚本执行的操作。所以我需要知道哪个--input文件--rotate正在引用

1 个答案:

答案 0 :(得分:1)

所以

python argparse_test.py --input 1.pdf --input 2.pdf --rotate

应该意味着 - 将rotate设置为True 2.pdf,因为它遵循该名称,但1.pdf保留为False,因为它没有--rotate国旗跟着吗?

它不能那样工作。标记的参数如--rotate--input可以按任何顺序出现。并且store_true参数无法像append一样在--input模式下运行。

可能有效的替代方案:

--input as nargs=2
python argparse_test.py --input 1.pdf 0 --input 2.pdf 1
Namespace(input=[['1.pdf','0'], ['2.pdf','1']])

--input as nargs='+'
python argparse_test.py --input 1.pdf --input 2.pdf 1
Namespace(input=[['1.pdf'], ['2.pdf','1']])

换句话说,用户在文件名后面添加一个字符串,表示是否要旋转。

我打算为append_const建议rotate,但是无法在列表中插入默认值。

我可以想象定义一对自定义动作类 - 见下文。

我认为Waylan建议的是有2个append列表,一个用于应该轮换的文件,另一个用于不应该用的文件。

您如何在使用和帮助信息中传达这样的要求?在开发过程中你可能看起来合乎逻辑,对于其他用户来说可能不那么明显,或者从现在开始六个月后对你自己也不那么明显。


自定义操作类似乎符合要求。这不是一个微不足道的定制,但也不是一个复杂或模糊的定制。它确实需要对argparse代码有一些详细的了解。

import argparse

class Input_action(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        # assume attribute has already been set to []
        items = getattr(namespace, self.dest)
        items.append(values)
        setattr(namespace, self.dest, items)

        dest = 'file_rotate'
        values = False
        items = getattr(namespace, dest)
        items.append(values)
        setattr(namespace, dest, items)

class Rotate_action(argparse._StoreTrueAction):

    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, self.const)
        dest = 'file_rotate'  # not same as self.dest
        items = getattr(namespace, dest)
        if items:
            items[-1] = True
        setattr(namespace, dest, items)

parser = argparse.ArgumentParser()
parser.add_argument('-i','--input', action=Input_action)
parser.add_argument('-r','--rotate', action=Rotate_action)

parser.print_help()

# simpler to initialize these attributes here than in the Actions
ns = argparse.Namespace(input=[], file_rotate=[])
print parser.parse_args(namespace=ns)

输出:

1030:~/mypy$ python stack28967342.py -i one -r -i two -i three -r
usage: stack28967342.py [-h] [-i INPUT] [-r]

optional arguments:
  -h, --help            show this help message and exit
  -i INPUT, --input INPUT
  -r, --rotate
Namespace(file_rotate=[True, False, True], input=['one', 'two', 'three'], rotate=True)

请注意结果命名空间中的2个列表。不需要rotate属性,但删除它需要更多工作。 help并未表明选项的特殊配对。


这是一个备用的Action对,它使用一个列表和带有name和rotate属性的复合对象。概括这种方法可能更容易。

class MyObj(argparse._AttributeHolder):
    "simple class to hold name and various attributes"
    def __init__(self, filename):
        self.name = filename
        self.rotate = False
        # define other defaults here

class Input_action(argparse._AppendAction):
    def __call__(self, parser, namespace, values, option_string=None):
        items = argparse._ensure_value(namespace, self.dest, [])
        items.append(MyObj(values))
        setattr(namespace, self.dest, items)

class Rotate_action(argparse._StoreTrueAction):

    def __call__(self, parser, namespace, values, option_string=None):
        # with default=SUPPRESS, rotate does not appear in namespace
        dest = 'input'  # could make this a parameter
        items = getattr(namespace, dest)
        if items:
            items[-1].rotate = True
        # no need to set, since I'm just modifying an existing object

parser = argparse.ArgumentParser()
parser.add_argument('-i','--input', action=Input_action,
    help='create a default input object with this name')
parser.add_argument('-r','--rotate', action=Rotate_action, default=argparse.SUPPRESS,
    help = 'set rotate attribute of preceeding input object')

parser.print_help()
print parser.parse_args()

生成像

这样的args
Namespace(input=[MyObj(name='one', rotate=True), MyObj(name='two', rotate=False), MyObj(name='three', rotate=True)])