Python中的参数依赖关系

Python中的参数依赖关系

本文介绍了Python中的参数依赖关系-无法使其工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试向脚本添加参数依赖项.这个想法是-clone 参数将需要非空的-gituser .

I am trying to add a parameter dependency to my script. The idea is that --clone argument will require non-empty --gituser.

仔细阅读此示例后,我尝试了以下

After perusing this example, I tried the following

In [93]: class CloneAction(argparse.Action):
    ...:     def __call__(self, parser, namespace, _):
    ...:         if not namespace.git_user and namespace.clone:
    ...:             parser.error('"--clone" requires legal git user')
    ...:
In [94]: parser = argparse.ArgumentParser()

In [95]: parser.add_argument('-g', '--gituser', dest='git_user', type=str, default='', action=CloneAction)
Out[95]: CloneAction(option_strings=['-g', '--gituser'], dest='git_user', nargs=None, const=None, default='', type=<type 'str'>, choices=None, help=None, metavar=None)

In [96]: parser.add_argument('--clone', action='store_true', default=False)
Out[96]: _StoreTrueAction(option_strings=['--clone'], dest='clone', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)

A,它没用

In [97]: parser.parse_args(['--clone'])
Out[97]: Namespace(clone=True, git_user='')

我做错了什么?

推荐答案

这种内部参数依存关系更容易在 解析之后实现.

This kind of inter argument dependency is easier to implement after parsing.

args = parser.parse_args()
if not namespace.git_user and namespace.clone:
    parser.error('"--clone" requires legal git user')

到那时,git_userclone都已被解析,并具有它们的最终值.

At that point, both git_user and clone have been parsed, and have their final values.

在实现它时,仅在有--gituser参数时才运行自定义操作.因此,我认为在不带--clone的情况下给它--gituser时,它将引发错误.

As you implemented it, the custom action is run only when there's a --gituser argument. So I think it will raise the error when you give it --gituser without --clone.

您可以给--clone一个类似的自定义操作,但是它也必须处理store_true详细信息.而--clone --gituser value序列会发生什么? clone操作将在解析gituser值之前运行.这样的测试会遇到一些棘手的参数顺序问题.

You could give --clone a similar custom action, but it would also have to handle the store_true details. And what should happen with the --clone --gituser value sequence? The clone action will be run before the gituser value has been parsed. Tests like this run into some tough argument order problems.

其他一些问题:

  • 您的自定义操作不存储任何值,无论是否出错.最好自定义store子类.

自定义操作应引发argparse.ArgumentError,而不是直接调用parser.error.

custom actions should raise argparse.ArgumentError rather than call parser.error directly.

单元测试文件test/test_argparse.py带有这样的相互测试的自定义操作示例.但这只是一个玩具,验证是否允许这样的代码.

The unittest file, test/test_argparse.py has an example of custom actions with mutual tests like this. But it's just a toy, verifying that such code is allowed.

=================

==================

从理论上讲,您可以实现--clone动作,该动作可以设置--gituser动作的required属性.这样,如果不使用--gituser,则parse_args的最终required动作测试将引发错误.但这需要保存对out[95]中显示的操作的引用(或在parse._actions列表中找到该引用.可行但混乱.

You could, in theory, implement a --clone action that sets the required attribute of the --gituser Action. That way, if --gituser is not used, the final required actions test of parse_args will raise an error. But that requires saving a reference to the Action displayed in out[95] (or finding that in the parse._actions list. Feasible but messy.

==================

===================

这是来自test/test_argparse.py的一对交互的自定义​​操作类的示例.

Here's an example of a pair of interacting custom action classes from test/test_argparse.py.

class OptionalAction(argparse.Action):

    def __call__(self, parser, namespace, value, option_string=None):
        try:
            # check destination and option string
            assert self.dest == 'spam', 'dest: %s' % self.dest
            assert option_string == '-s', 'flag: %s' % option_string
            # when option is before argument, badger=2, and when
            # option is after argument, badger=<whatever was set>
            expected_ns = NS(spam=0.25)
            if value in [0.125, 0.625]:
                expected_ns.badger = 2
            elif value in [2.0]:
                expected_ns.badger = 84
            else:
                raise AssertionError('value: %s' % value)
            assert expected_ns == namespace, ('expected %s, got %s' %
                                              (expected_ns, namespace))
        except AssertionError:
            e = sys.exc_info()[1]
            raise ArgumentParserError('opt_action failed: %s' % e)
        setattr(namespace, 'spam', value)

NSargparse.Namespace的简写.

class PositionalAction(argparse.Action):

    def __call__(self, parser, namespace, value, option_string=None):
        try:
            assert option_string is None, ('option_string: %s' %
                                           option_string)
            # check destination
            assert self.dest == 'badger', 'dest: %s' % self.dest
            # when argument is before option, spam=0.25, and when
            # option is after argument, spam=<whatever was set>
            expected_ns = NS(badger=2)
            if value in [42, 84]:
                expected_ns.spam = 0.25
            elif value in [1]:
                expected_ns.spam = 0.625
            elif value in [2]:
                expected_ns.spam = 0.125
            else:
                raise AssertionError('value: %s' % value)
            assert expected_ns == namespace, ('expected %s, got %s' %
                                              (expected_ns, namespace))
        except AssertionError:
            e = sys.exc_info()[1]
            raise ArgumentParserError('arg_action failed: %s' % e)
        setattr(namespace, 'badger', value)

它们用于

parser = argparse.ArgumentParser()
parser.add_argument('-s', dest='spam', action=OptionalAction,
        type=float, default=0.25)
parser.add_argument('badger', action=PositionalAction,
        type=int, nargs='?', default=2)

并应与以下产品一起使用:

And supposed to work with:

'-s0.125' producing: NS(spam=0.125, badger=2)),
'42',                NS(spam=0.25, badger=42)),
'-s 0.625 1',        NS(spam=0.625, badger=1)),
'84 -s2',            NS(spam=2.0, badger=84)),

这是可以执行的那种交叉检查的示例.但我会重复一遍,通常,交互最好在解析后而不是在解析后处理.

This is an example of the kind of cross checking that can be done. But I'll repeat that generally interactions are best handled after parsing, not during.

关于实现问题-如果用户不给您--gituser,则永远不会调用您的自定义操作. optionalAction.__call__仅在使用该参数时使用.始终使用positionals,但不使用optionals.

As to the implementation question - if the user does not give you --gituser, your custom Action is never called. The Action.__call__ of an optional is only used when that argument is used. positionals are always used, but not optionals.

这篇关于Python中的参数依赖关系-无法使其工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 15:52