所以
python argparse_test.py --input 1.pdf --input 2.pdf --rotate
应该意味着 - 为 2.pdf 设置 rotate 为 True 因为它遵循该名称,但为 1.pdf 设置为 False 因为它后面没有 --rotate 标志?
它不能那样工作。像--rotate 和--input 这样的标记参数可以以任何顺序出现。并且store_true 参数不能像您的--input 那样在append 模式下运行。
一些可能有效的替代方案:
--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']])
也就是说,用户在文件名后面加了一个字符串,表示是否要旋转。
我本来打算为rotate 推荐一个append_const,但无法在列表中插入默认值。
我可以想象定义一对自定义动作类 - 见下文。
我认为 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 没有表示任何关于选项的特殊配对。
这是一个备用动作对,它与一个列表和具有名称和旋转属性的复合对象一起使用。推广这种方法可能更容易。
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()
产生类似的参数
Namespace(input=[MyObj(name='one', rotate=True), MyObj(name='two', rotate=False), MyObj(name='three', rotate=True)])