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

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

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

if verbose:
    print ...

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

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

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

+68
источник поделиться
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

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

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

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

+85
источник

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

+48
источник

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

+9
источник

Построение и упрощение ответа @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()

В этом случае вы используете следующее script:

v_print(1, "INFO message")
v_print(2, "WARN message")
v_print(3, "ERROR message")

И ваш script можно вызвать следующим образом:

% 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

Несколько примечаний:

  • Ваш первый аргумент - ваш уровень ошибки, а второй - ваше сообщение. Он имеет магическое число 3, которое устанавливает верхнюю границу для вашего ведения журнала, но я принимаю это как компромисс для простоты.
  • Если вы хотите, чтобы v_print работал во всей вашей программе, вам нужно сделать хлам с глобальным. Это не весело, но я призываю кого-то найти лучший способ.
+7
источник

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

+2
источник

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

+2
источник

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

Я хочу иметь возможность изменять глобальный параметр "verbose" в любое время. Простота и удобочитаемость для меня имеют первостепенное значение. Поэтому я бы сказал, что следующие строки указывают:

[email protected]:~$ 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" также может быть задана из списка параметров.

0
источник

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

if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
0
источник

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

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос