我使用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
正在引用
答案 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()
生成像
这样的argsNamespace(input=[MyObj(name='one', rotate=True), MyObj(name='two', rotate=False), MyObj(name='three', rotate=True)])