Python 如何在脚本中实现--verbose或-v选项?

Python 如何在脚本中实现--verbose或-v选项?,python,option,Python,Option,我从几个工具中了解了--verbose或-v,我想在我自己的一些脚本和工具中实现这一点 我想把: if verbose: print ... 通过我的源代码,这样,如果用户通过-v选项,变量verbose将设置为True,并打印文本 这是正确的方法还是有更普遍的方法 另外:我不是在寻求一种实现参数解析的方法。我知道这是怎么做的。我只对verbose选项特别感兴趣。如果您有一个函数,比如称为vprint,可以为您检查verbose标志,那么它可能会更干净。然后,您只需调用自己的vprin

我从几个工具中了解了
--verbose
-v
,我想在我自己的一些脚本和工具中实现这一点

我想把:

if verbose:
    print ...
通过我的源代码,这样,如果用户通过
-v
选项,变量
verbose
将设置为
True
,并打印文本

这是正确的方法还是有更普遍的方法


另外:我不是在寻求一种实现参数解析的方法。我知道这是怎么做的。我只对verbose选项特别感兴趣。

如果您有一个函数,比如称为
vprint
,可以为您检查verbose标志,那么它可能会更干净。然后,您只需调用自己的
vprint
函数,您可以在任何需要可选详细信息的地方调用该函数。

我的建议是使用函数。但是,与其将
if
放入函数中(您可能会尝试这样做),不如这样做:

if verbose:
    def verboseprint(*args):
        # Print each argument separately so caller doesn't need to
        # stuff everything to be printed into a single string
        for arg in args:
           print arg,
        print
else:   
    verboseprint = lambda *a: None      # do-nothing function
% python verbose-tester.py -v
ERROR message

% python verbose=tester.py -vv
WARN message
ERROR message

% python verbose-tester.py -vvv
INFO message
WARN message
ERROR message
if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
(是的,您可以在
if
语句中定义函数,并且只有在条件为true时才能定义该函数!)

如果您使用的是Python 3,
print
已经是一个函数(或者如果您愿意使用
print
作为2.x中的一个函数,使用
from uuuu future\uuuuuuu导入print\u函数
),则更简单:

verboseprint = print if verbose else lambda *a, **k: None
这样,函数被定义为关闭冗余模式(使用lambda)时不执行任何操作,而不是不断测试
verbose
标志

如果用户可以在程序运行期间更改详细模式,这将是错误的方法(您需要函数中的
If
),但由于您使用命令行标志设置它,因此您只需要做出一次决定


然后,当您想要打印“verbose”消息时,可以使用例如
verboseprint(“查看我所有的详细信息!”,object(),3)

我在脚本中所做的是在运行时检查是否设置了“verbose”选项,然后将日志记录级别设置为debug。如果未设置,则将其设置为“信息”。这样,您的代码中就不会出现“if verbose”检查

构建和简化@kindall的答案,以下是我通常使用的:

v_print = None
def main()
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbosity', action="count", 
                        help="increase output verbosity (e.g., -vv is more than -v)")

    args = parser.parse_args()

    if args.verbosity:
        def _v_print(*verb_args):
            if verb_args[0] > (3 - args.verbosity):
                print verb_args[1]  
    else:
        _v_print = lambda *a: None  # do-nothing function

    global v_print
    v_print = _v_print

if __name__ == '__main__':
    main()
然后在整个脚本中提供以下用法:

v_print(1, "INFO message")
v_print(2, "WARN message")
v_print(3, "ERROR message")
您的脚本可以这样调用:

if verbose:
    def verboseprint(*args):
        # Print each argument separately so caller doesn't need to
        # stuff everything to be printed into a single string
        for arg in args:
           print arg,
        print
else:   
    verboseprint = lambda *a: None      # do-nothing function
% python verbose-tester.py -v
ERROR message

% python verbose=tester.py -vv
WARN message
ERROR message

% python verbose-tester.py -vvv
INFO message
WARN message
ERROR message
if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
几点注意:

  • 第一个参数是错误级别,第二个参数是消息。它有一个神奇的数字
    3
    ,为您的日志设置了上限,但为了简单起见,我接受这一点
  • 如果您想在整个程序中使用
    v_print
    ,则必须使用全局打印。这一点都不好玩,但我要挑战别人找到更好的方法

  • 使用
    日志记录
    模块:

    将日志记录作为日志导入
    …
    args=p.parse_args()
    如果args.verbose:
    log.basicConfig(format=“%(levelname)s:%(message)s”,level=log.DEBUG)
    log.info(“详细输出”)
    其他:
    log.basicConfig(格式=“%(levelname)s:%(消息)s”)
    log.info(“这应该是详细的。”)
    log.warning(“这是一个警告”)
    log.error(“这是一个错误”)
    
    所有这些都会自动转到
    stderr

    %python myprogram.py
    警告:这是一个警告。
    错误:这是一个错误。
    %python myprogram.py-v
    信息:详细输出。
    信息:这应该是冗长的。
    警告:这是一个警告。
    错误:这是一个错误。
    

    有关更多信息,请参阅和。

    我为我的一个项目偷了。查看
    virtualenv.py
    main()
    ,查看代码中是否散布了
    logger.notify()
    logger.info()
    logger.warn()
    ,等等。实际发出输出的方法取决于virtualenv是否是使用
    -v
    -vv
    -vvv
    、或
    -q
    调用的。我需要的是一个打印对象(obj)的函数,但只有当全局变量verbose为true时,否则它不会执行任何操作

    我希望能够随时更改全局参数“verbose”。简单性和可读性对我来说至关重要。因此,我将按照以下几行指示进行:

    ak@HP2000:~$ python3
    Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
    [GCC 4.8.4] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> verbose = True
    >>> def vprint(obj):
    ...     if verbose:
    ...         print(obj)
    ...     return
    ... 
    >>> vprint('Norm and I')
    Norm and I
    >>> verbose = False
    >>> vprint('I and Norm')
    >>> 
    
    全局变量“verbose”也可以从参数列表中设置。

    不适用于我的Python版本3.5@styles在他的评论中正确地指出原因是附加的可选关键字参数。因此,我对Python 3稍微改进的版本如下所示:

    if verbose:
        def verboseprint(*args):
            # Print each argument separately so caller doesn't need to
            # stuff everything to be printed into a single string
            for arg in args:
               print arg,
            print
    else:   
        verboseprint = lambda *a: None      # do-nothing function
    
    % python verbose-tester.py -v
    ERROR message
    
    % python verbose=tester.py -vv
    WARN message
    ERROR message
    
    % python verbose-tester.py -vvv
    INFO message
    WARN message
    ERROR message
    
    if VERBOSE:
        def verboseprint(*args, **kwargs):
            print(*args, **kwargs)
    else:
        verboseprint = lambda *a, **k: None # do-nothing function
    

    可能有一个全局变量,可能是由
    sys.argv
    中的
    argparse
    设置的,表示程序是否应该详细。 然后,可以编写一个decorator,这样,如果启用了verbosity,那么只要函数运行,标准输入就会转移到null设备中:

    import os
    from contextlib import redirect_stdout
    verbose = False
    
    def louder(f):
        def loud_f(*args, **kwargs):
            if not verbose:
                with open(os.devnull, 'w') as void:
                    with redirect_stdout(void):
                        return f(*args, **kwargs)
            return f(*args, **kwargs)
        return loud_f
    
    @louder
    def foo(s):
        print(s*3)
    
    foo("bar")
    
    这个答案的灵感来自于;实际上,我打算在我的程序中将它作为一个模块使用,但我遇到了一些我无法理解的错误,所以我修改了它的一部分

    此解决方案的缺点是,冗余是二进制的,这与
    日志记录不同,后者允许对程序的冗余程度进行更精细的调整。
    
    另外,所有
    打印
    调用都被转移,这可能是不需要的。

    为什么不使用日志模块,默认设置日志级别信息,并在传递--verbose时进行调试?最好不要重新实现该语言中已有的任何东西…@Tim,我同意,但是日志模块非常痛苦。更好的是,使用
    print
    函数:接受许多参数。它可以在3.x中实现为
    print(*args)
    ,在2.x中实现为args中arg的
    :print arg、
    。主要的优点是,它允许在一条消息中混合字符串和其他类型的内容,而无需显式的
    str
    调用/格式化和连接。在
    print arg,
    行末尾使用的逗号是什么?这很容易由个人自行实验或通过检查