¿Cómo implementar la opción verb verbose o-v en un script?


Conozco el --verbose o -v de varias herramientas y me gustaría implementar esto en algunos de mis propios scripts y herramientas.

Pensé en colocar

if verbose:
    print ...

A través de mi código fuente, de modo que si un usuario pasa la opción -v, la variable verbose se establecerá en True y el texto se imprimirá.

¿Es este el enfoque correcto o hay una manera más común?

Adición: No estoy pidiendo una manera de implementar el análisis de argumentos. Que sé cómo se hace. Me solo estoy interesado especialmente en la opción detallada. ¡Gracias!

Author: Qantas 94 Heavy, 2011-05-12

9 answers

Mi sugerencia es usar una función. Pero en lugar de poner el if en la función, que usted podría ser tentado a hacer, hacerlo así:{[11]]}

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

(Sí, puede definir una función en una instrucción if, ¡y solo se definirá si la condición es verdadera!)

Si estás usando Python 3, donde print ya es una función (o si estás dispuesto a usar print como una función en 2.x usando from __future__ import print_function) es aún más simple:

verboseprint = print if verbose else lambda *a, **k: None

De esta manera, la función se define como no hacer nada si el modo detallado está desactivado (usando una lambda), en lugar de probar constantemente el indicador verbose.

Si el usuario pudiera cambiar el modo de verbosidad durante la ejecución de su programa, este sería el enfoque equivocado (necesitaría el if en la función), pero como lo está configurando con una bandera de línea de comandos, solo necesita tomar la decisión una vez.

A continuación, utilice, por ejemplo, verboseprint("look at all my verbosity!", object(), 3) cada vez que desee imprimir un mensaje "detallado".

 83
Author: kindall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-12 16:35:13

Utilice el módulo 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.")

Todos estos van automáticamente a 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.

Para obtener más información, consulte los documentos de Python y los tutoriales .

 47
Author: Profpatsch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-14 15:04:53

Lo que hago en mis scripts es comprobar en tiempo de ejecución si la opción 'verbose' está establecida, y luego establecer mi nivel de registro para depurar. Si no está configurado, lo establezco en info. De esta manera no tienes 'si verbose' comprueba todo tu código.

 9
Author: jonesy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-12 15:12:22

Construyendo y simplificando la respuesta de @kindall, esto es lo que normalmente uso:

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()

Esto proporciona el siguiente uso a lo largo de su script:

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

Y su script se puede llamar así:

% 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

Un par de notas:

  1. Su primer argumento es su nivel de error, y el segundo es su mensaje. Tiene el número mágico de 3 que establece el límite superior para su registro, pero lo acepto como un compromiso para la simplicidad.
  2. Si quieres v_print para trabajar a lo largo de su programa, usted tiene que hacer la basura con el global. No es divertido, pero reto a alguien a encontrar una mejor manera.
 8
Author: mlissner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-08 01:08:25

Podría ser más limpio si tiene una función, digamos llamada vprint, que comprueba la bandera detallada por usted. A continuación, simplemente llame a su propia función vprint en cualquier lugar que desee verbosidad opcional.

 2
Author: Lee-Man,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-12 15:06:27

Robé el código de registrode virtualenv para un proyecto mío. Mira en main() de virtualenv.py para ver cómo se inicializa. El código está salpicado de logger.notify(), logger.info(), logger.warn(), y el como. Qué métodos realmente emiten salida está determinado por si virtualenv fue invocado con -v, -vv, -vvv, o -q.

 2
Author: George V. Reilly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-08 20:51:35

Lo que necesito es una función que imprima un objeto (obj), pero solo si la variable global verbose es verdadera, de lo contrario no hace nada.

Quiero poder cambiar el parámetro global "verbose" en cualquier momento. La simplicidad y la legibilidad para mí son de suma importancia. Así que procedería como las siguientes líneas indican:

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')
>>> 

La variable global "verbose" también se puede establecer desde la lista de parámetros.

 0
Author: user377367,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-29 01:18:21

@la solución de kindall no funciona con mi versión 3.5 de Python. @styles indica correctamente en su comentario que la razón es el argumento opcional adicional keywords. Por lo tanto, mi versión ligeramente refinada para Python 3 se ve así:

if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
 0
Author: stefanct,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:39

Podría haber una variable global, probablemente establecida con argparse de sys.argv, que representa si el programa debe ser detallado o no. Entonces un decorador podría ser escrito de tal manera que si verbosity estuviera activado, entonces la entrada estándar sería desviada hacia el dispositivo nulo siempre y cuando la función fuera ejecutada:

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")

Esta respuesta está inspirada en este código ; en realidad, iba a usarlo como un módulo en mi programa, pero tengo errores que no podía entender, así que adapté una parte de se.

La desventaja de esta solución es que la verbosidad es binaria, a diferencia de logging, lo que permite un ajuste más fino de cuán detallado puede ser el programa. También, todos print las llamadas se desvían, lo que podría ser no deseado para.

 0
Author: Daniel Diniz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-04 11:55:55