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

时间:2011-05-12 15:01:40

标签: python option

我知道来自多个工具的--verbose-v,我想将其实现到我自己的一些脚本和工具中。

我想放置:

if verbose:
    print ...

通过我的源代码,以便在用户通过-v选项时,变量verbose将设置为True并且文本将被打印。

这是正确的方法还是有更常见的方式?

另外:我不是要求一种方法来实现参数的解析。我知道它是如何完成的。我只对这个详细的选项感兴趣。

9 个答案:

答案 0 :(得分:89)

我的建议是使用一个功能。但是,不要将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

(是的,您可以在if语句中定义一个函数,只有在条件为真时才会定义它!)

如果您使用的是Python 3,print已经是一个函数(或者如果您愿意使用printfrom __future__ import print_function用作2.x中的函数,那么它就是甚至更简单:

verboseprint = print if verbose else lambda *a, **k: None

这样,如果详细模式关闭(使用lambda),则该函数被定义为无操作,而不是不断测试verbose标志。

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

然后使用例如只要您想要打印“详细”消息,就verboseprint("look at all my verbosity!", object(), 3)

答案 1 :(得分:52)

使用logging模块:

import logging as log
…
args = p.parse_args()
if args.verbose:
    log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
    log.info("Verbose output.")
else:
    log.basicConfig(format="%(levelname)s: %(message)s")

log.info("This should be verbose.")
log.warning("This is a warning.")
log.error("This is an error.")

所有这些都会自动转到stderr

% python myprogram.py
WARNING: This is a warning.
ERROR: This is an error.

% python myprogram.py -v
INFO: Verbose output.
INFO: This should be verbose.
WARNING: This is a warning.
ERROR: This is an error.

有关详细信息,请参阅Python Docstutorials

答案 2 :(得分:10)

建立并简化@ 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")

您的脚本可以像这样调用:

% 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

一对夫妇注意到:

  1. 您的第一个参数是您的错误级别,第二个参数是您的消息。它具有设置记录上限的3幻数,但我接受这是为了简单起见。
  2. 如果您希望v_print在整个程序中运行,则必须使用全局进行垃圾处理。这并不好玩,但我挑战某人找到更好的方法。

答案 3 :(得分:9)

我在脚本中执行的操作是在运行时检查是否设置了'verbose'选项,然后将我的日志记录级别设置为debug。如果没有设置,我将其设置为info。这样,您就不会在代码中进行“if verbose”检查。

答案 4 :(得分:2)

如果你有一个函数,比如叫vprint,它可能会更清晰,它会为你检查详细标记。然后你可以在任何想要选择性详细程度的地方调用你自己的vprint函数。

答案 5 :(得分:2)

我从the logging code偷了virtualenv我的一个项目。查看main()的{​​{1}}以查看how it's initialized.代码中包含virtualenv.pylogger.notify()logger.info()等。实际发出输出的方法取决于是否使用logger.warn()-v-vv-vvv调用virtualenv。

答案 6 :(得分:1)

可能存在一个全局变量,可能是argparsesys.argv设置的,表示该程序是否应该是详细的。 然后可以编写一个装饰器,如果开启了详细程度,那么只要该函数运行,标准输入就会被转移到空设备中:

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")

这个答案的灵感来自this code;实际上,我只是将它用作我程序中的一个模块,但是我遇到了我无法理解的错误,所以我调整了它的一部分。

这个解决方案的缺点是详细程度是二进制的,与logging不同,它允许更精细地调整程序的详细程度。 此外,所有 print来电都被转移,这可能是不受欢迎的。

答案 7 :(得分:0)

我需要的是一个打印对象(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')
>>> 

全局变量"详细"也可以从参数列表中设置。

答案 8 :(得分:0)

@kindall's solution不适用于我的Python 3.5版。 @styles在他的评论中正确地指出原因是附加的可选关键字参数。因此,我对Python 3的略微改进的版本看起来像这样:

template<typename T>
class ScopeGuard
{
public:
    ScopeGuard(const ScopeGuard&) = delete;
    ScopeGuard& operator=(const ScopeGuard&) = delete;

    explicit ScopeGuard(T&& func) :
        func_(std::forward<T>(func))
    {}

    ScopeGuard(ScopeGuard&& right) :
        func_(std::move(right.func_))
    {}

    ~ScopeGuard()
    {
        if (!dismissed_) func_();
    }

    void Dismiss()
    {
        dismissed_ = true;
    }

private:
    T func_;
    bool dismissed_ = false;
};

template<typename T>
__forceinline ScopeGuard<T> GenerateScopeGuard(T&& func) noexcept
{
    return ScopeGuard<T>(std::forward<T>(func));
}

int main()
{
    auto func = GenerateScopeGuard([] {printf("hello\n"); });
    return 0;
}