Как реализовать параметр --verbose или -v в скрипте? - PullRequest
75 голосов
/ 12 мая 2011

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

Я думал о размещении:

if verbose:
    print ...

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

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

Дополнение: я не прошу способ реализовать разбор аргументов.Это я знаю, как это делается.Меня особенно интересует подробный вариант.

Ответы [ 9 ]

91 голосов
/ 12 мая 2011

Я предлагаю использовать функцию.Но вместо того, чтобы помещать 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 выключен (используется лямбда), вместо того, чтобы постоянно проверятьverbose флаг.

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

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

52 голосов
/ 14 марта 2013

Используйте модуль 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 и учебные пособия .

11 голосов
/ 08 февраля 2013

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

В моих скриптах я проверяю, установлена ​​ли во время выполнения опция «verbose», и затем устанавливаю уровень ведения журнала на отладку.Если он не установлен, я установил его на информацию.Таким образом, вы не будете проверять весь код.

2 голосов
/ 07 июня 2013

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

2 голосов
/ 12 мая 2011

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

1 голос
/ 04 июня 2018

Может существовать глобальная переменная, вероятно, установленная с 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 вызовы переадресованы, что может быть нежелательным для.

1 голос
/ 10 сентября 2016

Решение @ kindall не работает с моим Python версии 3.5. @styles правильно заявляет в своем комментарии, что причиной является дополнительный необязательный аргумент keyword . Следовательно, моя слегка улучшенная версия для Python 3 выглядит следующим образом:

if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
0 голосов
/ 29 декабря 2015

Мне нужна функция, которая печатает объект (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" также может быть установлена ​​из списка параметров.

...