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



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



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



if verbose:
print ...


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



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



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

373   9  

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 флаг.

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

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

Comments

    Ничего не найдено.