【问题标题】:Check if argparse optional argument is set or not检查是否设置了 argparse 可选参数
【发布时间】:2015-08-09 20:27:00
【问题描述】:

我想检查用户是否设置了可选的 argparse 参数。

我可以使用 isset 安全地检查吗?

类似这样的:

if(isset(args.myArg)):
    #do something
else:
    #do something else

这对于 float / int / string 类型的参数是否同样有效?

我可以设置一个默认参数并检查它(例如,设置 myArg = -1,或“”为字符串,或“NOT_SET”)。但是,我最终要使用的值仅在脚本的后面计算。因此,我会将其默认设置为 -1,然后稍后将其更新为其他内容。与简单地检查值是否由用户设置相比,这似乎有点笨拙。

【问题讨论】:

  • isset() 会是什么(提示:Python 不是 PHP)?你的意思是hasattr() 吗?为什么不配置 argparse 来为选项设置默认值?
  • @MartijnPieters - 是的,是的。那么我可以简单地检查一下 if(args.myArg): ...

标签: python argparse


【解决方案1】:

我认为如果未提供可选参数(用-- 指定),它们将被初始化为None。因此您可以使用is not None 进行测试。试试下面的例子:

import argparse

def main():
    parser = argparse.ArgumentParser(description="My Script")
    parser.add_argument("--myArg")
    args, leftovers = parser.parse_known_args()

    if args.myArg is not None:
        print "myArg has been set (value is %s)" % args.myArg

【讨论】:

  • “is None”和“is not None”测试完全符合我的期望。谢谢。
  • 不幸的是它不起作用然后参数得到它的default值定义。
  • 如果您想设置default,那么您仍然可以设置nargs='?' 并提供const 值,如in the docs 所述。当 arg 不存在时,使用 default,当 arg 给定 w/o 值时,则使用 const,否则使用给定值。只有defaultnargs='?',如果没有给出default,如果给出没有值,则使用None,否则给出值。
  • @IoannisFilippidis 如果您使用 action= "store_true"action="store_const", const="yourconst" 您不能使用该参数来存储其他值。这在使用默认值时不起作用。在我自己的情况下,我已经从 argparser 中删除了所有默认值,并在另一个函数 def defaults(): 中处理了所有默认值,我在其中按我想要的顺序混合了 ConfigParser、ArgumentParser 和默认值
  • @erm3nda 我没有提到设置action。答案不使用action。您提到的操作被记录为以一种特定的方式表现(如您所观察到的)。不过,没有必要定义一个动作。
【解决方案2】:

正如@Honza 所说,is None 是一个很好的测试。这是默认的default,用户不能给你一个重复它的字符串。

您可以指定另一个default='mydefaultvalue',并对其进行测试。但是如果用户指定了那个字符串呢?这算不算设置?

您也可以指定default=argparse.SUPPRESS。那么如果用户不使用该参数,它就不会出现在args 命名空间中。但测试可能更复杂:

parser.add_argument("--foo", default=argparse.SUPPRESS)

# ...

args.foo # raises an AttributeError
hasattr(args, 'foo')  # returns False
getattr(args, 'foo', 'other') # returns 'other'

parser 在内部保留seen_actions 的列表,并将其用于“必需”和“互斥”测试。但在parse_args 之外,您无法使用它。

【讨论】:

    【解决方案3】:

    我认为使用选项default=argparse.SUPPRESS 最有意义。然后,不是检查参数是否为not None,而是检查参数是否为in 生成的命名空间。

    示例:

    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument("--foo", default=argparse.SUPPRESS)
    ns = parser.parse_args()
    
    print("Parsed arguments: {}".format(ns))
    print("foo in namespace?: {}".format("foo" in ns))
    

    用法:

    $ python argparse_test.py --foo 1
    Parsed arguments: Namespace(foo='1')
    foo in namespace?: True
    
    不提供参数:
    $ python argparse_test.py
    Parsed arguments: Namespace()
    foo in namespace?: False
    

    【讨论】:

    • 这在 Python 3.7.5 (Anaconda) 下对我不起作用。我得到结果testfoo.py: error: argument --foo: expected one argument
    • 我只是按照答案中的说明复制并粘贴了您的代码。也许你应该编辑它?我最终在我的实际代码中使用了下面的action='store_true' 答案。
    • @MikeWise 你是否以python argparse_test.py --foo 1 运行脚本?
    • 这是否也适用于互斥组?
    【解决方案4】:

    您可以使用store_truestore_false 参数操作选项检查可选传递的标志:

    import argparse
    
    argparser = argparse.ArgumentParser()
    argparser.add_argument('-flag', dest='flag_exists', action='store_true')
    
    print argparser.parse_args([])
    # Namespace(flag_exists=False)
    print argparser.parse_args(['-flag'])
    # Namespace(flag_exists=True)
    

    这样,您不必担心通过条件is not None 进行检查。您只需检查TrueFalse。在文档here

    中阅读有关这些选项的更多信息

    【讨论】:

    • 这并不能确定是否设置了具有值的参数。这里的主要问题是要知道 args 值是来自 defaul="" 还是由用户提供。
    【解决方案5】:

    如果您的参数是位置(即它没有“-”或“--”前缀,只有参数,通常是文件名),那么您可以使用the nargs parameter这样做:

    parser = argparse.ArgumentParser(description='Foo is a program that does things')
    parser.add_argument('filename', nargs='?')
    args = parser.parse_args()
    
    if args.filename is not None:
        print('The file name is {}'.format(args.filename))
    else:
        print('Oh well ; No args, no problems')
    

    【讨论】:

      【解决方案6】:

      为了解决@kcpr 对@Honza Osobne 的(当前接受的)答案的评论

      不幸的是它不起作用然后参数得到了它的默认值 已定义。

      首先可以通过将参数与Namespace 对象进行比较并提供default=argparse.SUPPRESS 选项来检查参数是否已提供(请参阅@hpaulj 和@Erasmus Cedernaes 的答案以及此python3 doc)以及是否尚未提供提供,然后将其设置为默认值。

      import argparse
      
      parser = argparse.ArgumentParser()
      parser.add_argument('--infile', default=argparse.SUPPRESS)
      args = parser.parse_args()
      if 'infile' in args: 
          # the argument is in the namespace, it's been provided by the user
          # set it to what has been provided
          theinfile = args.infile
          print('argument \'--infile\' was given, set to {}'.format(theinfile))
      else:
          # the argument isn't in the namespace
          # set it to a default value
          theinfile = 'your_default.txt'
          print('argument \'--infile\' was not given, set to default {}'.format(theinfile))
      

      用法

      $ python3 testargparse_so.py
      argument '--infile' was not given, set to default your_default.txt
      
      $ python3 testargparse_so.py --infile user_file.txt
      argument '--infile' was given, set to user_file.txt
      

      【讨论】:

        【解决方案7】:

        这是我是否使用 argparse 变量的解决方案

        import argparse
        
        ap = argparse.ArgumentParser()
        ap.add_argument("-1", "--first", required=True)
        ap.add_argument("-2", "--second", required=True)
        ap.add_argument("-3", "--third", required=False) 
        # Combine all arguments into a list called args
        args = vars(ap.parse_args())
        if args["third"] is not None:
        # do something
        

        这可能会更深入地了解我使用并适用于我的程序的上述答案。

        【讨论】:

          【解决方案8】:

          这里有一个稍微不同的方法:
          假设您知道参数名称,那么您可以执行以下操作:

          import sys
          
          def is_set(arg_name):
              if arg_name in sys.argv:
                  return True 
              return False
          

          这样你就不需要改变你的参数解析器,仍然可以添加你的自定义逻辑。

          【讨论】:

          • 这是个好主意,但有一个问题:argparse 允许在没有歧义的情况下对可选参数进行部分匹配。 (例如,如果您有一个标志 --option,那么如果没有其他以 "opt" 开头的标志,--opt 将起作用。)如果您在 sys.argv 中查找以开头的条目,则可以修改此方法以使其正常工作但是,具有选项中最短的唯一部分。
          【解决方案9】:

          自定义操作可以解决此问题。而且我发现它并没有那么复杂。

          is_set = set() #global set reference
          class IsStored(argparse.Action):
              def __call__(self, parser, namespace, values, option_string=None):
                  is_set.add(self.dest) # save to global reference
                  setattr(namespace, self.dest + '_set', True) # or you may inject directly to namespace
                  setattr(namespace, self.dest, values) # implementation of store_action
                  # You cannot inject directly to self.dest until you have a custom class
          
          
          parser.add_argument("--myarg", type=int, default=1, action=IsStored)
          params = parser.parse_args()
          print(params.myarg, 'myarg' in is_set)
          print(hasattr(params, 'myarg_set'))
          

          【讨论】:

            【解决方案10】:

            很简单,通过 'args = parser.parse_args()' 定义 args 变量后,它也包含了 args 子集变量的所有数据。假设使用了 'action="store_true" 来检查是否设置了变量...

            if args.argument_name:
               # do something
            else:
               # do something else
            

            【讨论】:

              猜你喜欢
              • 2016-07-19
              • 2013-01-22
              • 2015-12-29
              • 2012-05-28
              • 2018-07-16
              • 1970-01-01
              • 1970-01-01
              • 2011-05-27
              相关资源
              最近更新 更多