【问题标题】:Using a file to store optparse arguments使用文件存储 optparse 参数
【发布时间】:2011-10-14 17:31:58
【问题描述】:

我已经使用 optparse 有一段时间了,并且想添加从配置文件加载参数的功能。

到目前为止,我能想到的最好的方法是一个带有硬编码参数的包装批处理脚本......看起来很笨重。

最优雅的方法是什么?

【问题讨论】:

    标签: python optparse


    【解决方案1】:

    我同意 S.Lott 使用配置文件的想法,但我建议使用内置的 ConfigParser(3.0 中的 configparser)模块来解析它,而不是自制的解决方案。

    这是一个简短的脚本,说明了 ConfigParser 和 optparse 的作用。

    import ConfigParser
    from optparse import OptionParser
    
    CONFIG_FILENAME = 'defaults.cfg'
    
    def main():
        config = ConfigParser.ConfigParser()
        config.read(CONFIG_FILENAME)
    
        parser = OptionParser()
        parser.add_option("-l",
                          "--language",
                          dest="language",
                          help="The UI language",
                          default=config.get("Localization", "language"))
        parser.add_option("-f",
                          "--flag",
                          dest="flag",
                          help="The country flag",
                          default=config.get("Localization", "flag"))
    
        print parser.parse_args()
    
    if __name__ == "__main__":
        main()
    

    输出:

    (<Values at 0x2182c88: {'flag': 'japan.png', 'language': 'Japanese'}>, [])
    

    使用“parser.py --language=French”运行:

    (<Values at 0x2215c60: {'flag': 'japan.png', 'language': 'French'}>, [])
    

    帮助是内置的。 使用“parser.py --help”运行:

    Usage: parser.py [options]
    
    Options:
      -h, --help            show this help message and exit
      -l LANGUAGE, --language=LANGUAGE
                            The UI language
      -f FLAG, --flag=FLAG  The country flag
    

    配置文件:

    [Localization]
    language=Japanese
    flag=japan.png
    

    【讨论】:

      【解决方案2】:

      您可以为此使用argparse 模块:

      >>> open('args.txt', 'w').write('-f\nbar')
      >>> parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
      >>> parser.add_argument('-f')
      >>> parser.parse_args(['-f', 'foo', '@args.txt'])
      Namespace(f='bar')
      

      它可能包含在标准库中,请参阅pep 389

      【讨论】:

      • PEP 389 获得批准,argparse 已经是 Python 2.7 的一部分
      【解决方案3】:

      我遇到了类似的问题,但也想将配置文件指定为参数。受 S. Lott 的回答启发,我想出了以下代码。

      示例终端会话:

      $ python defaultconf.py # 使用硬编码的默认值
      错误的
      $ python defaultconf.py --verbose # 命令行详细
      真的
      $ python defaultconf.py --loadconfig blah # 加载配置 'verbose':True
      真的
      $ python defaultconf.py --loadconfig blah --quiet # 覆盖配置值
      错误

      代码:

      #!/usr/bin/env python2.6
      import optparse
      
      def getParser(defaults):
          """Create and return an OptionParser instance, with supplied defaults
          """
          o = optparse.OptionParser()
          o.set_defaults(**defaults)
          o.add_option("--verbose", dest = "verbose", action="store_true")
          o.add_option("--quiet", dest = "verbose", action="store_false")
      
          o.add_option("--loadconfig", dest = "loadconfig")
      
          return o
      
      
      def main():
          # Hard coded defaults (including non-command-line-argument options)
          my_defaults = {'verbose': False, 'config_only_variable': 42}
      
          # Initially parse arguments
          opts, args = getParser(my_defaults).parse_args()
      
          if opts.loadconfig is not None:
              # Load config from disk, update the defaults dictionary, and reparse
              # Could use ConfigParser, simplejson, yaml etc.
      
              config_file_values = {'verbose': True} # the dict loaded from disk
      
              my_defaults.update(config_file_values)
              opts, args = getParser(my_defaults).parse_args()
      
          print opts.verbose
      
      if __name__ == '__main__':
          main()
      

      一个实用的实现可以在 Github 上找到:The defaults dictionarythe argument parserthe main function

      【讨论】:

      • 太好了。我已经扩展它以在 --help: 中显示配置文件中的默认值
      【解决方案4】:

      这就是set_defaults 函数的用途。 http://docs.python.org/library/optparse.html#optparse.OptionParser.set_defaults

      创建一个作为默认值字典的文件。

      { 'arg1': 'this',
      'arg2': 'that'
      }
      

      然后读取此文件,对其进行评估以将文本转换为字典,并将此字典作为参数提供给set_defaults

      如果您真的担心eval,那么请对该文件使用 JSON(或 YAML)表示法。或者您甚至可以从中创建一个.INI 文件并使用configparser 来获取您的默认值。

      或者您可以使用简单的赋值语句列表和exec

      配置文件。

      arg1 = 'this'
      arg2 = 'that'
      

      读取配置文件。

      defaults= {}
      with open('defaults.py','r') as config
          exec config in {}, defaults
      

      【讨论】:

      • 这里没有理由使用 eval - 你可以使用 marshal。
      • @Nick Bastin:Eval 不是邪恶的,只有那些总是试图通过利用 eval 来破解应用程序的反社会最终用户。
      • 利用你盔甲上的缝隙向攻击者挥动手指既不会消除缝隙也不会阻止攻击...... :)
      • @Kevin Litle:这个神秘的“攻击者”是谁?同事?购买应用程序的人?具体是谁?请提供这个神秘的“攻击者”的名字。
      • @S.很多 ;) : 我不知道这个神秘的攻击者是谁——这是问题的一部分!我也不知道这个小小的、“安全”的 Python 小程序(我将在其中插入一个外部可访问文件的裸露的“eval()”)将在三年内结束。也许它会成为我从未想过的漂亮公共服务的一部分,通过信任我在写完一年后离开的公司/社区中的开发人员巧妙地融合在一起。但是,我们离题了;对不起!
      【解决方案5】:

      以相同的命令行格式从文件中读取参数,例如@commands,然后使用您的原始解析器来解析它们。

      options, args = parser.parse_args()
      
      if args[0][0] == '@': # script.py @optfile 
          with open(args[0][1:]) as f:
              fa = [l.strip() for l in f]
          fa = fa + args[1:] # put back any other positional arguments
          # Use your original parser to parse the new options
          options, args = parser.parse_args(args=fa, values=options)
      

      【讨论】:

        【解决方案6】:

        我最近构建了很多带有标志和选项的脚本,并且我想出了here 描述的解决方案。

        基本上,我实例化了一个带有特殊标志的选项解析器,该标志告诉尝试从文件中加载选项,因此您可以正常使用脚本从命令行指定选项或从文件中提供它们(或一组)。

        更新:我在GitHub上分享了代码

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-08-26
          • 1970-01-01
          • 2018-07-23
          • 2012-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-22
          相关资源
          最近更新 更多