python argparse 总是设置与可选参数相关的默认值
python argparse always set defaults related to an optional argument
我使用 python 3,我想将 argparse 设置为始终设置与我选择的预定义可选参数相关的默认键。
例如我将一些输入文件传递给脚本。可选参数指定输入文件是否应由脚本旋转。我得到了一个输入文件列表,但我还想要一个相同大小的列表,其中包含 '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
这是输出
Namespace(input=['1.pdf', '2.pdf'], rotate=True)
但我想要这个输出
Namespace(input=['1.pdf', '2.pdf'], rotate=[False,True])
请注意,--rotate
可以是我在 --input
文件上编写的 python 脚本必须在 --rotate
本身之前执行的任何操作。所以我需要知道哪个 --input
文件 --rotate
指的是
所以
python argparse_test.py --input 1.pdf --input 2.pdf --rotate
的意思是 - 对于 2.pdf
将 rotate
设置为 True 因为它遵循该名称,但对于 1.pdf
将其保留为 False 因为没有 --rotate
flag 跟随它?
这样不行。 --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)])
我使用 python 3,我想将 argparse 设置为始终设置与我选择的预定义可选参数相关的默认键。
例如我将一些输入文件传递给脚本。可选参数指定输入文件是否应由脚本旋转。我得到了一个输入文件列表,但我还想要一个相同大小的列表,其中包含 '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
这是输出
Namespace(input=['1.pdf', '2.pdf'], rotate=True)
但我想要这个输出
Namespace(input=['1.pdf', '2.pdf'], rotate=[False,True])
请注意,--rotate
可以是我在 --input
文件上编写的 python 脚本必须在 --rotate
本身之前执行的任何操作。所以我需要知道哪个 --input
文件 --rotate
指的是
所以
python argparse_test.py --input 1.pdf --input 2.pdf --rotate
的意思是 - 对于 2.pdf
将 rotate
设置为 True 因为它遵循该名称,但对于 1.pdf
将其保留为 False 因为没有 --rotate
flag 跟随它?
这样不行。 --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)])