Python Argparse:必需的参数';y';如果';x';存在

Python Argparse:必需的参数';y';如果';x';存在,python,argparse,Python,Argparse,我的要求如下: ./xyifier --prox --lport lport --rport rport 对于参数prox,我使用action='store\u true'检查它是否存在。 我不需要任何论据。但是,如果设置了--prox,我还需要rport和lport。有没有一种简单的方法可以在不编写自定义条件编码的情况下使用argparse实现这一点 更多代码: non_int.add_argument('--prox', action='store_true', help='Flag to

我的要求如下:

./xyifier --prox --lport lport --rport rport
对于参数prox,我使用action='store\u true'检查它是否存在。 我不需要任何论据。但是,如果设置了--prox,我还需要rport和lport。有没有一种简单的方法可以在不编写自定义条件编码的情况下使用argparse实现这一点

更多代码:

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', type=int, help='Listen Port.')
non_int.add_argument('--rport', type=int, help='Proxy port.')

不,argparse中没有任何选项可以生成相互包含的选项集

解决这一问题的最简单方法是:

if args.prox and (args.lport is None or args.rport is None):
    parser.error("--prox requires --lport and --rport.")

当未设置
prox
时,是否使用
lport
。如果不是,为什么不使用
prox
lport
rport
参数?e、 g

parser.add_argument('--prox', nargs=2, type=int, help='Prox: listen and proxy ports')

这样可以节省用户的打字时间。如果args.prox不是None:,那么测试
就和测试
如果args.prox:

一样简单:
您说的是有条件地需要参数。就像@borntyping所说的,您可以检查错误并执行
parser.error()
,或者您可以在添加新参数时应用与
--prox
相关的要求

对于您的示例,一个简单的解决方案可以是:

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', required='--prox' in sys.argv, type=int)
non_int.add_argument('--rport', required='--prox' in sys.argv, type=int)
通过这种方式,
required
接收
True
False
,具体取决于用户是否使用了
--prox
。这也保证了
-lport
-rport
在彼此之间具有独立的行为。

如果存在
--prox
,则使用方法,然后添加
--lport
--rport
参数作为所需的参数

# just add --prox arg now
non_int = argparse.ArgumentParser(description="stackoverflow question", 
                                  usage="%(prog)s [-h] [--prox --lport port --rport port]")
non_int.add_argument('--prox', action='store_true', 
                     help='Flag to turn on proxy, requires additional args lport and rport')
opts, rem_args = non_int.parse_known_args()
if opts.prox:
    non_int.add_argument('--lport', required=True, type=int, help='Listen Port.')
    non_int.add_argument('--rport', required=True, type=int, help='Proxy port.')
    # use options and namespace from first parsing
    non_int.parse_args(rem_args, namespace = opts)
还要记住,在第二次解析其余参数时,可以提供第一次解析后生成的名称空间
opts
。这样,最后,在完成所有解析之后,您将拥有一个包含所有选项的名称空间

缺点:

  • 如果
    --prox
    不存在,则命名空间中甚至不存在其他两个相关选项。尽管基于您的用例,如果
    --prox
    不存在,那么其他选项的情况与此无关
  • 需要修改使用消息,因为解析器不知道完整的结构
  • --lport
    --rport
    不会显示在帮助消息中

    • 这个被接受的答案对我来说非常有用!因为所有的代码在没有测试的情况下都会被破坏,所以我在这里测试了被接受的答案
      parser.error()
      不会引发
      argparse.ArgumentError
      error,而是退出进程。您必须测试
      SystemExit

      用pytest

      import pytest
      from . import parse_arguments  # code that rasises parse.error()
      
      
      def test_args_parsed_raises_error():
          with pytest.raises(SystemExit):
              parse_arguments(["argument that raises error"])
      
      使用单元测试

      from unittest import TestCase
      from . import parse_arguments  # code that rasises parse.error()
      
      class TestArgs(TestCase):
      
          def test_args_parsed_raises_error():
              with self.assertRaises(SystemExit) as cm:
                  parse_arguments(["argument that raises error"])
      
      灵感来源:我是这样做的:

      if t or x or y:
          assert t and x and y, f"args: -t, -x and -y should be given together"
      

      这就是我最后为
      解析器所做的事。error
      方法,这就是我要找的!你不应该用“或”吗?毕竟,如果args.prox和(args.lport为None或args.rport为None)都需要args
      而不是
      args.lport为None
      ,只需使用
      而不是args.lport
      。我认为它有点像python。这会阻止您将
      --lport
      --rport
      设置为
      0
      ,这可能是程序的有效输入。为了完整起见,当您的NARG大于1时,您将在解析的参数等中获得一个列表,您可以用通常的方式对其进行处理。例如,
      a,b=args.prox
      a=args.prox[0]
      等。请注意,
      ArgumentParser
      可用于解析除
      sys.argv
      之外的列表中的参数,这种情况下会失败。如果使用
      --prox=
      语法,也会失败。然后,
      必需='--prox'in'。连接(sys argv)
      ,但我想提到我的图书馆。例如,让你做这个问题想要做的事情,而不必让你自己验证一切(如接受的答案中所示),也不必依靠漏洞破解(如投票数第二高的回答中所示)。对于来到这里的任何人,另一个令人惊奇的解决方案是: