传递解析的参数没有任何乐趣

时间:2016-05-27 06:35:32

标签: python design-patterns argparse

我在Python中使用arparse来解析命令行中的参数:

def main():
    parser = argparse.ArgumentParser(usage=usage)
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true')
    parser.add_argument(...)
    args = parser.parse_args()

我只在代码的几个地方使用对象args

有三种方法,调用堆栈看起来像这样

def first_level(args):
    second_level()

def second_level():
    third_level()

def third_level():
    ### here I want to add some logging if args.verbose is True

我想在third_level()添加一些日志记录。

我不想更改方法second_level()的签名。

如何在arg中提供third_lelvel()对象?

我可以将arg存储为全局变量,但有人告诉我几年前不要在开发人员培训中使用全局变量....

处理此问题的常用方法是什么?

2 个答案:

答案 0 :(得分:2)

将我的评论转换为答案。我建议你的third_level(..)根本没有条件。有一些机制可以让日志记录模块处理这些 - 并且可以从这3个函数之外控制这些机制。

类似的东西:

def first_level(args):
    second_level()

def second_level():
    third_level()

def third_level():
    logging.info("log line which will be printed if logging is at INFO level")


def main():
    args = ....
    #Set the logging level, conditionally
    if args.verbose:
        logging.basicConfig(filename='myapp.log', level=logging.INFO)
    else:
        logging.basicConfig(filename='myapp.log', level=logging.WARNING)

    first_level(args)

答案 1 :(得分:2)

常见的模块结构如下:

 imports ...
 <constants>
 options = {verbose=0, etc}
 # alt options = argparse.Namespace(logging=False,....)

 def levelone(args, **kwargs):
     ....
 def leveltwo(...):

 def levelthree(...):
     <use constant>
     <use options>

 def parser():
    p = argparse.ArgumentParser()
    ....
    args = p.parse_args()  # this uses sys.argv

 if __name__=='__main__':
      args = parser()
      options.update(vars(args))
      levelone(args)

模块的主体具有功能定义,可以由其他模块导入。如果用作脚本,则parser将读取命令行。全局options可用于各种state类似参数。从某种意义上说,它们是用户或导入模块可以调整的常量。从config文件导入的值可以具有相同的角色。

另一种常见模式是使您的函数方法成为一个类,并将args作为对象属性传递。

class Foo():
   def __init__(self, logging=False):
      self.logging = logging
   def levelone():
   def leveltwo():
      <use self.logging>
foo(args.logging).levelone()

虽然不鼓励globals,但更多是因为它们被过度使用,并破坏了功能提供的模块性。但是Python还提供了一个module级别的命名空间,它不仅包含函数和类。并且模块中定义的任何函数都可以访问该命名空间 - 除非它自己的定义会影响它。

 var1 = 'module level variable'
 var2 = 'another'
 def foo(var3):
    x = var1  # read/use var1
    var2 = 1   # shadow the module level definition
    etc

=====

我不确定是否应该推荐这个,但您可以在sys.argv内解析third_level

 def third_level():
     import argparse
     p = argparse.ArgumentParser()
     p.add_argument('-v','--verbose',action='count')
     args = p.parse_known_args()
     verbose = args.verbose
     <logging>

argparse导入sys并使用sys.argv。无论是在脚本级别,main还是某些嵌套函数中使用它,都可以执行此操作。 logging做同样的事情。您可以使用自己的导入模块将值隐式传递给函数。显然可以被滥用。具有类属性的class也可以这种方式使用。