Как реализовать параметр --verbose или-v в скрипте?

Я знаю --verbose или -v из нескольких инструментов, и я хотел бы реализовать это в некоторых моих собственных скриптах и инструментах.

Я думал о предоставлении

if verbose:
    print ...

через мой исходный код, так что если пользователь передает переменная verbose будет установлен в True и текст будет напечатан.

это правильный подход или есть более простой способ?

Addition: я не прошу способ реализации синтаксического анализа аргументов. Что я знаю, как это делается. Меня особенно интересует многословный вариант. Спасибо!

9 ответов


мое предложение-использовать функцию. Но вместо того, чтобы положить 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 уже является функцией (или если вы готовы использовать print как функция в 2.x использование from __future__ import print_function) это даже проще:

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

таким образом, функция определяется как ничего не делать, если подробный режим выключен (используя лямбда), а не постоянно тестировать verbose флаг.

если пользователь может изменить режим многословия во время бега вашей программы, это был бы неправильный подход (вам понадобится if в функции), но так как вы устанавливаете его с флагом командной строки, вам нужно только принять решение один раз.

затем вы используете например,verboseprint("look at all my verbosity!", object(), 3) всякий раз, когда вы хотите напечатать "многословный" сообщение.


использовать 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 Docs и уроки.


то, что я делаю в моих сценариях, - это проверка во время выполнения, если установлен параметр "подробный", а затем установите мой уровень ведения журнала в debug. Если он не установлен, я устанавливаю его в info. Таким образом, у вас нет проверки "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")

и ваш скрипт можно назвать так:

% 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 чтобы работать на протяжении всей вашей программы, вы должны делать мусор с глобальным. Это не весело, но я бросаю вызов кому-то, чтобы найти лучший путь.

Это может быть чище, если у вас есть функция, скажем под названием vprint, Это проверяет подробный флаг для вас. Тогда вы просто называете свой vprint функция любое место, где вы хотите дополнительную многословность.


украл ведение журнала код С virtualenv для моего проекта. Посмотрите в main() of virtualenv.py посмотреть как он инициализируется. код посыпают logger.notify(), logger.info(), logger.warn() и тому подобное. Какие методы фактически испускают вывод, определяется тем, был ли virtualenv вызван с -v, -vv, -vvv или -q.


Мне нужна функция, которая печатает объект (obj), но только если глобальная переменная verbose истинна, иначе она ничего не делает.

Я хочу иметь возможность изменять глобальный параметр "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" также может быть установлена из списка параметров.


@kindall это не работает с моей версией Python 3.5. @styles правильно заявляет в своем комментарии, что причиной является дополнительный необязательный ключевые слова


может быть глобальная переменная, вероятно, установленная с argparse С sys.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")

этот ответ навеян код; на самом деле, я собирался просто использовать его как модуль в своей программе, но у меня были ошибки, которые я не мог понять, поэтому Я адаптировал часть.

недостатком этого решения является то, что многословие является двоичным, в отличие от logging, что позволяет более тонкую настройку того, как многословная программа может быть. Кроме того,все print вызовы перенаправляются, которые могут быть нежелательными для.