如何子类化 argparse.Action 以添加自定义操作?
How do I subclass argparse.Action to add a custom action?
我有一个命令行脚本,我正在尝试 运行 如果该值不存在,它会将默认值插入到命名空间中,或者如果存在则按原样使用提供的参数。
所以我想这样做:
myscript.py --merge
将导致参数解析器命名空间如下所示:
Namespace(merge='--merge')
否则,如果我调用
myscript.py
命名空间应如下所示:
Namespace(merge='DONTMERGE')
我想我需要子class argparse.Action
class 的 __call__
方法来执行此处指定的自定义操作:https://pymotw.com/2/argparse/ 但是我不知道该怎么做。
我认为这样的事情可以解决问题:
class CustomAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if isinstance(self.values, None):
self.values = 'NOMERGE'
else:
self.values = '--nomerge'
setattr(namespace, self.dest, values)
很遗憾,我没有得到预期的结果。
我认为你只需要一个正常的 store_const
参数。
parser.add_argument('--merge', action='store_const', const='MERGE', default='DONTMERGE')
如果您使用 --merge
调用脚本,merge
参数采用值 MERGE
(上面指定为 const
)。否则,merge
参数采用值 DONTMERGE
(上面指定为 default
)。
您要求的确切内容不可能通过子类化 Action
来实现。原因是 CustomAction
实例被 __call__
编辑 当且仅当 --merge
传递给参数解析器:
class CustomAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
print("Yay, I've been called")
setattr(namespace, self.dest, values)
p = argparse.ArgumentParser()
p.add_argument('--merge', nargs='?', action=CustomAction)
print(p.parse_args([]))
print(p.parse_args(['--merge']))
Namespace(merge=None)
Yay, I've been called
Namespace(merge=None)
这里我必须传递 nargs='?'
,否则 argparse 需要 --merge
.
的参数
许多 Action
覆盖 Action.__init__(...)
,但它无法访问解析器的命名空间 ¯\_(ツ)_/¯
如果你想完全使用子类,你可能必须对 ArgumentParser
本身进行子类化并修改 add_argument()
方法。
虽然可以用 Actions 做一些很酷的 and/or 奇怪的事情:
class ReverseAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, ''.join(reversed(values)))
p = argparse.ArgumentParser()
p.add_argument('--string', action=ReverseAction)
print(p.parse_args(['--string', '12345']))
Namespace(string='54321')
(我唯一一次自己创建argparse.Action
的子类是为了实现高级验证)
至于你的具体情况,在我看来这只是一份简单的工作 action='store_true'
:
>>> parser.add_argument('--merge', action='store_true')
_StoreTrueAction(option_strings=['--merge'], dest='merge', nargs=0, const=True,
default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args(['--merge'])
Namespace(merge=True)
>>> parser.parse_args([])
Namespace(merge=False)
…甚至 BooleanOptionalAction
(在 Python >=3.9 中):
>>> parser.add_argument('--merge', action=argparse.BooleanOptionalAction, default=False)
BooleanOptionalAction(option_strings=['--merge', '--no-merge'], dest='merge', nargs=0,
const=None, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args([])
Namespace(merge=False)
>>> parser.parse_args(['--no-merge'])
Namespace(merge=False)
>>> parser.parse_args(['--merge'])
Namespace(merge=True)
照例看argparse docs and/or源代码=)
我有一个命令行脚本,我正在尝试 运行 如果该值不存在,它会将默认值插入到命名空间中,或者如果存在则按原样使用提供的参数。
所以我想这样做:
myscript.py --merge
将导致参数解析器命名空间如下所示:
Namespace(merge='--merge')
否则,如果我调用
myscript.py
命名空间应如下所示:
Namespace(merge='DONTMERGE')
我想我需要子class argparse.Action
class 的 __call__
方法来执行此处指定的自定义操作:https://pymotw.com/2/argparse/ 但是我不知道该怎么做。
我认为这样的事情可以解决问题:
class CustomAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if isinstance(self.values, None):
self.values = 'NOMERGE'
else:
self.values = '--nomerge'
setattr(namespace, self.dest, values)
很遗憾,我没有得到预期的结果。
我认为你只需要一个正常的 store_const
参数。
parser.add_argument('--merge', action='store_const', const='MERGE', default='DONTMERGE')
如果您使用 --merge
调用脚本,merge
参数采用值 MERGE
(上面指定为 const
)。否则,merge
参数采用值 DONTMERGE
(上面指定为 default
)。
您要求的确切内容不可能通过子类化 Action
来实现。原因是 CustomAction
实例被 __call__
编辑 当且仅当 --merge
传递给参数解析器:
class CustomAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
print("Yay, I've been called")
setattr(namespace, self.dest, values)
p = argparse.ArgumentParser()
p.add_argument('--merge', nargs='?', action=CustomAction)
print(p.parse_args([]))
print(p.parse_args(['--merge']))
Namespace(merge=None)
Yay, I've been called
Namespace(merge=None)
这里我必须传递 nargs='?'
,否则 argparse 需要 --merge
.
许多 Action
覆盖 Action.__init__(...)
,但它无法访问解析器的命名空间 ¯\_(ツ)_/¯
如果你想完全使用子类,你可能必须对 ArgumentParser
本身进行子类化并修改 add_argument()
方法。
虽然可以用 Actions 做一些很酷的 and/or 奇怪的事情:
class ReverseAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, ''.join(reversed(values)))
p = argparse.ArgumentParser()
p.add_argument('--string', action=ReverseAction)
print(p.parse_args(['--string', '12345']))
Namespace(string='54321')
(我唯一一次自己创建argparse.Action
的子类是为了实现高级验证)
至于你的具体情况,在我看来这只是一份简单的工作 action='store_true'
:
>>> parser.add_argument('--merge', action='store_true')
_StoreTrueAction(option_strings=['--merge'], dest='merge', nargs=0, const=True,
default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args(['--merge'])
Namespace(merge=True)
>>> parser.parse_args([])
Namespace(merge=False)
…甚至 BooleanOptionalAction
(在 Python >=3.9 中):
>>> parser.add_argument('--merge', action=argparse.BooleanOptionalAction, default=False)
BooleanOptionalAction(option_strings=['--merge', '--no-merge'], dest='merge', nargs=0,
const=None, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args([])
Namespace(merge=False)
>>> parser.parse_args(['--no-merge'])
Namespace(merge=False)
>>> parser.parse_args(['--merge'])
Namespace(merge=True)
照例看argparse docs and/or源代码=)