--verbose 또는 -v 옵션을 스크립트에 구현하는 방법은 무엇입니까?


95

나는 알고 --verbose또는 -v여러 툴을 나는 내 자신의 스크립트와 도구의 일부에이를 구현하고 싶습니다.

나는 배치를 생각했다 :

if verbose:
    print ...

내 소스 코드를 통해 사용자가 -v옵션을 전달 하면 변수 verbose가로 설정되고 True텍스트가 인쇄됩니다.

이것이 올바른 접근 방식입니까 아니면 더 일반적인 방법이 있습니까?

추가 : 인수 구문 분석을 구현하는 방법을 요구하지 않습니다. 나는 그것이 어떻게 행해지는지 압니다. 나는 verbose 옵션에만 특별히 관심이 있습니다.


9
로깅 모듈을 사용하고 기본적으로 로그 수준 INFO를 설정하고 --verbose가 전달되면 DEBUG를 설정하지 않는 이유는 무엇입니까? 이미 언어로 제공되는 것을 다시 구현하지 않는 것이 가장
Tim

3
@ 팀, 동의하지만 로깅 모듈은 매우 고통 스럽습니다.
mlissner 2013

답변:


109

내 제안은 기능을 사용하는 것입니다. 그러나 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명령문 에서 함수를 정의 할 수 있으며 조건이 참인 경우에만 정의됩니다!)

print이미 함수가 있는 Python 3 을 사용하는 경우 ( 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)"verbose"메시지를 인쇄 할 때마다 예를 사용 합니다.


1
더 좋은 점은 print함수 로 수행하는 것 입니다. 많은 인수를 허용하십시오. print(*args)3.x 및 for arg in args: print arg,2.x에서 와 같이 구현할 수 있습니다 . 주요 장점은 명시적인 str호출 / 형식화 및 연결 없이 하나의 메시지에서 문자열과 다른 유형의 것들을 혼합 할 수 있다는 것입니다 .

print arg,줄 끝에서 사용되는 쉼표는 무엇입니까 ?
SamK

그것은 실험적으로 또는 문서를 확인하여 쉽게 결정할 수 있지만 일반적으로 인쇄되는 줄 바꿈을 억제합니다.
kindall 2012-08-07

5
Python 3 인쇄 함수는 또한 선택적 키워드 인수를 취하므로 인쇄 기능을 완전히 재현하기 위해 :def verboseprint(*args, **kwargs): print(*args, **kwargs)
lstyls

63

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 문서자습서를 참조 하세요 .


8
여기에 있는 Python 문서 에 따라 프로그램의 정상적인 실행에서 출력 만 인쇄해야하는 경우 로깅을 사용해서는 안됩니다. OP가 원하는 것 같습니다.
SANDeveloper

1
이것은 기본적인 문제에 대해서는 괜찮아 보이지만 많은 * nix 명령은 여러 수준의 상세도 (-v -v -v 등)를 지원하므로 이런 식으로 지저분해질 수 있습니다.
TextGeek

12

@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프로그램 전체에서 일하고 싶다면 글로벌과 함께 쓰레기를 처리해야합니다. 재미는 없지만 더 나은 방법을 찾기 위해 누군가에게 도전합니다.

1
INFO 및 WARN에 로깅 모듈을 사용하지 않는 이유는 무엇입니까? -v사용 하면 가져옵니다 . 현재 솔루션에서는 모든 것이 stderr 대신 stdout에 덤프됩니다. 그리고 : 일반적으로 모든 오류를 사용자에게 전달하고 싶지 않습니까?
Profpatsch 2013 년

2
예, 그게 공정한 요점입니다. 로깅은 내가 피하려고했던인지 오버 헤드를 가지고 있지만 아마도 "올바른"일일 것입니다. 그냥 ... 과거에 나를 짜증이야
mlissner

9

스크립트에서 내가하는 일은 런타임에 'verbose'옵션이 설정되어 있는지 확인한 다음 로깅 수준을 디버그로 설정하는 것입니다. 설정되어 있지 않으면 info로 설정합니다. 이렇게하면 코드 전체에 대해 '장황한 경우'검사를 수행 할 필요가 없습니다.


2

vprintverbose 플래그를 확인 하는 함수가 있으면 더 깨끗할 수 있습니다 . 그런 다음 vprint원하는 자세한 기능을 원하는 곳에서 자신의 함수를 호출하십시오 .



2

@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

1

가능성 설정 전역 변수가있을 수 있습니다 argparse에서 sys.argv프로그램이 자세한 여부를 수 있는지 여부를 의미합니다. 그런 다음 데코레이터를 작성하여 상세도가 켜져 있으면 함수가 실행되는 한 표준 입력이 null 장치로 전환됩니다.

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

내가 필요한 것은 객체 (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"도 설정할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.