Wiem, że --verbose
albo -v
z kilku narzędzi i chciałbym zaimplementować to w niektórych moich własnych skryptów i narzędzi.
Myślałem o umieszczeniu:
if verbose:
print ...
poprzez mój kod źródłowy, więc jeśli użytkownik przekaże -v
opcję, zmienna verbose
zostanie ustawiona na, True
a tekst zostanie wydrukowany.
Czy to właściwe podejście, czy też jest bardziej powszechny sposób?
Dodatek: nie proszę o sposób implementacji parsowania argumentów. Że wiem, jak to się robi. Szczególnie interesuje mnie tylko opcja gadatliwa.
Odpowiedzi:
Moja sugestia to użycie funkcji. Ale zamiast umieszczać funkcję
if
w funkcji, o którą możesz się kusić, zrób to w następujący sposób: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
(Tak, możesz zdefiniować funkcję w
if
instrukcji, a zostanie ona zdefiniowana tylko wtedy, gdy warunek jest prawdziwy!)Jeśli używasz Pythona 3, gdzie
print
jest już funkcją (lub jeśli chcesz użyć jejprint
jako funkcji w wersji 2.x przy użyciufrom __future__ import print_function
), jest to jeszcze prostsze:verboseprint = print if verbose else lambda *a, **k: None
W ten sposób funkcja jest definiowana jako nic nie rób, jeśli tryb gadatliwy jest wyłączony (przy użyciu lambda), zamiast ciągłego testowania
verbose
flagi.Gdyby użytkownik mógł zmienić tryb oznajmiania podczas wykonywania programu, byłoby to niewłaściwe podejście (potrzebowałbyś
if
funkcji), ale ponieważ ustawiasz go flagą wiersza poleceń, musisz tylko podejmij decyzję raz.Możesz wtedy użyć np. Zawsze,
verboseprint("look at all my verbosity!", object(), 3)
gdy chcesz wydrukować "gadatliwą" wiadomość.źródło
print
funkcję: Akceptuj wiele argumentów. Może być zaimplementowany tak jakprint(*args)
w 3.x ifor arg in args: print arg,
2.x. Główną zaletą jest to, że umożliwia mieszanie łańcuchów i rzeczy innych typów w jednej wiadomości bez jawnychstr
wywołań / formatowania i konkatenacji.print arg,
wiersza?def verboseprint(*args, **kwargs): print(*args, **kwargs)
Skorzystaj z
logging
modułu: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.")
Wszystkie z nich automatycznie trafiają do
stderr
:Aby uzyskać więcej informacji, zobacz dokumentację języka Python i samouczki .
źródło
Budując i upraszczając odpowiedź @ kindall, oto czego zwykle używam:
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()
Zapewnia to następujące użycie w całym skrypcie:
v_print(1, "INFO message") v_print(2, "WARN message") v_print(3, "ERROR message")
A twój skrypt można nazwać w ten sposób:
Kilka uwag:
3
która wyznacza górną granicę dla twojego logowania, ale przyjmuję to jako kompromis dla prostoty.v_print
pracować nad całym programem, musisz pozbyć się śmieci z globalnymi. To nie jest zabawne, ale rzucam wyzwanie komuś, aby znalazł lepszy sposób.źródło
-v
jest używany. W obecnym rozwiązaniu wszystko jest zrzucane na stdout zamiast na stderr. I: normalnie chcesz przekazać użytkownikowi każdy błąd, prawda?To, co robię w moich skryptach, to sprawdzanie w czasie wykonywania, czy opcja „verbose” jest ustawiona, a następnie ustawianie poziomu rejestrowania na debugowanie. Jeśli nie jest ustawiony, ustawiam go na info. W ten sposób nie masz sprawdzania „if verbose” w całym kodzie.
źródło
Może to być czystsze, jeśli masz funkcję, powiedzmy wywołaną
vprint
, która sprawdza za Ciebie flagę gadatliwości. Następnie po prostu wywołujesz swojąvprint
funkcję w dowolnym miejscu, w którym chcesz opcjonalną szczegółowość.źródło
Ukradłem kod logowania z virtualenv do mojego projektu. Zajrzyj
main()
do,virtualenv.py
aby zobaczyć, jak jest zainicjowany. Kod jest posypanelogger.notify()
,logger.info()
,logger.warn()
, i tym podobne. Jakie metody faktycznie wyjście emitować określenia czy virtualenv została wywołana z-v
,-vv
,-vvv
, lub-q
.źródło
Rozwiązanie @ kindall nie działa z moim Pythonem w wersji 3.5. @styles poprawnie stwierdza w swoim komentarzu, że powodem jest dodatkowy opcjonalny argument słów kluczowych . Stąd moja nieco dopracowana wersja dla Pythona 3 wygląda tak:
if VERBOSE: def verboseprint(*args, **kwargs): print(*args, **kwargs) else: verboseprint = lambda *a, **k: None # do-nothing function
źródło
Mogłaby istnieć zmienna globalna, prawdopodobnie ustawiona za pomocą
argparse
fromsys.argv
, która określa , czy program powinien być gadatliwy, czy nie. Następnie można by napisać dekorator w taki sposób, że gdyby była włączona gadatliwość, standardowe wejście byłoby przekierowane do urządzenia zerowego, o ile funkcja miałaby działać: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")
Ta odpowiedź jest inspirowana tym kodem ; właściwie zamierzałem użyć go po prostu jako modułu w moim programie, ale dostałem błędy, których nie mogłem zrozumieć, więc dostosowałem część z nich.
Wadą tego rozwiązania jest to, że gadatliwość jest binarna, w przeciwieństwie do with
logging
, co pozwala na dokładniejsze dostrojenie tego, jak rozwlekły może być program. Ponadto wszystkieprint
połączenia są przekierowywane, co może być niepożądane.źródło
Potrzebuję funkcji, która drukuje obiekt (obj), ale tylko wtedy, gdy zmienna globalna verbose jest prawdziwa, w przeciwnym razie nic nie robi.
Chcę mieć możliwość zmiany globalnego parametru „verbose” w dowolnym momencie. Prostota i czytelność są dla mnie najważniejsze. Więc postąpiłbym tak, jak wskazują następujące linie:
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') >>>
Z listy parametrów można również ustawić zmienną globalną „verbose”.
źródło