2009-10-24 16 views
11

A veces dejo las declaraciones de impresión de depuración en mi proyecto y es difícil encontrarlo. ¿Hay alguna forma de averiguar qué línea está imprimiendo algo en particular?Encontrar una instrucción de impresión en Python

Nota al margen

Parece que la búsqueda inteligente puede resolver la mayoría de los casos. En Pydev (y otros IDEs) hay una función de búsqueda que permite buscar a través de todos los archivos en un proyecto. Por supuesto, se puede obtener un efecto similar usando grep con el indicador -rn, aunque solo se obtienen números de línea en lugar de enlaces directos.

"print (" funciona mucho mejor dentro de mi código y a menudo hay texto adicional en una declaración de impresión que se puede buscar con una expresión regular. El caso más difícil es cuando acaba de escribir print (x), aunque esto se puede buscar una expresión regular, donde el valor dentro de x no empieza ni termina con citas

+0

¿Qué editor de texto y sistema operativo ...? –

+0

Uso de Pydev en Eclipse – Casebash

+0

El establecimiento de un tracefunc lo activará para todas las llamadas, sin importar cómo se escribieron. – Geo

Respuesta

27

Preguntas sobre soluciones estáticas. Aquí hay uno dinámico. Supongamos que ejecuta el código y ve una impresión errónea o escribe en sys.stdout, y desea saber de dónde proviene. Puede reemplazar sys.stdout y dejar que la excepción de rastreo ayuda que:

>>> import sys 
>>> def go(): 
... sys.stdout = None 
... print "Hello!" 
... 
>>> go() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in go 
AttributeError: 'NoneType' object has no attribute 'write' 
>>> print "Here" 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'NoneType' object has no attribute 'write' 
>>> 

Para algo un poco más sofisticado, reemplace 'sys.stdout' con algo que depende donde se encuentra la declaración de impresión. Utilizaré traceback.print_stack() para mostrar la pila completa, pero puede hacer otras cosas como usar sys._getframe() para buscar un nivel de pila para obtener el número de línea y el nombre del archivo.

import sys 
import traceback 

class TracePrints(object): 
    def __init__(self):  
    self.stdout = sys.stdout 
    def write(self, s): 
    self.stdout.write("Writing %r\n" % s) 
    traceback.print_stack(file=self.stdout) 

sys.stdout = TracePrints() 

def a(): 
    print "I am here" 

def b(): 
    a() 

b() 

Aquí está la salida

Writing 'I am here' 
    File "stdout.py", line 19, in <module> 
    b() 
    File "stdout.py", line 17, in b 
    a() 
    File "stdout.py", line 14, in a 
    print "I am here" 
    File "stdout.py", line 9, in write 
    traceback.print_stack(file=self.stdout) 
Writing '\n' 
    File "stdout.py", line 19, in <module> 
    b() 
    File "stdout.py", line 17, in b 
    a() 
    File "stdout.py", line 14, in a 
    print "I am here" 
    File "stdout.py", line 9, in write 
    traceback.print_stack(file=self.stdout) 

Si usted va esta ruta, consulta el módulo 'linecache', que se puede utilizar para imprimir el contenido de la línea. Eche un vistazo a la implementación de traceback.print_stack para obtener detalles sobre cómo hacerlo.

+0

¡Gracias, eso es genio! – Casebash

+0

Esta es una gran respuesta. ¡Gracias por compartir! –

+0

¡Simple y genio! –

4

uso grep (gracias BecomingGuro!):

grep -rn print .

+0

Buena suerte con bibliotecas de terceros, marcos de JavaScript, archivos binarios y otras sutilezas – dangonfast

1

el uso de grep con una expresión regular inteligentemente construida (hace no comenzar ni finalizar con comillas) parece ser su mejor opción.

+0

Realmente debería usar la búsqueda de expresiones regulares más. Sin embargo, como se señaló anteriormente, hay algunos casos que esto no cubre – Casebash

+0

"no comienza ni termina con comillas": es un truco brillante. – Casebash

+0

¿Qué hay de malo en buscar solo "imprimir"? oh espera ... ¿es esa la inteligente expresión regular? – hasen

5

This article puede resultar muy valioso para hacer eso. Busque los eventos line y extraiga el nombre del método del marco (si no recuerdo mal). Se puede encontrar más información here

+0

Guau, eso es totalmente increíble. Puedo imaginar algunos hacks geniales como agregar un ## al final de cada línea que quieras seguir. Puede terminar siendo lento, pero sería posible escribir una versión que almacena en caché las llamadas y, por lo tanto, cada línea solo tiene que examinarse una vez – Casebash

+0

Una característica interesante aquí, pero tenga cuidado al usarla para crear un código completamente inmaterial ... – vy32

+0

Creo que es principalmente para la depuración – Casebash

2

La manera más fácil sería usar una función "debug_print" en lugar de una "impresión" simple.

De esta manera podría redefinir la función y asegúrese de no perder uno ... y todavía tenerlos a mano si necesita depurar ese código nuevamente en lugar de editar su código de ida y vuelta cada vez.

(Sí dejando llamadas debug_print puede comer algo de rendimiento: simplemente eliminarlos cuando es el caso)

Spotting "depuración sólo" declaraciones en su código es una muy buena razón para hacer una diff antes comitting cualquier código en tu sistema de control de revisiones (¡Saber qué poner en los comentarios de compromiso es una segunda buena razón para hacerlo!)

+0

El problema con esto es que esto requiere un mayor esfuerzo para escribir y ralentizaría la depuración. Tal vez debería definir mi declaración como _p – Casebash

+1

¿No sería mejor usar el módulo 'logging' en su lugar? Si recuerdo correctamente, puede desactivarse cuando no lo necesite (para que no pierda rendimiento cuando no lo necesite). – Geo

+0

Estoy de acuerdo con Geo, el uso del módulo de registro sería mucho más limpio, eso es lo que está hecho. – RedGlyph

0

Esto probablemente no responda su pregunta directamente, pero puede salirse con toneladas de declaraciones de impresión si usa pdb (depurador de python) en una forma de depurar y escribir código de manera efectiva.

Sé que funciona, porque el 99% del tiempo usted simplemente no quiere imprimir cosas, pero desea establecer un punto de interrupción en algún lugar y ver cuáles son las variables y qué tan lejos ha llegado el programa.

HTH

+0

En realidad estoy usando el depurador de Pydev y de hecho puede ver las variables/expresiones simplemente con el mouse sobre la selección que es muy buena – Casebash

0

Me suelen hacer esto en mi código:

(cerca de la parte superior):

debug=True 

(más adelante)

si depuración : imprimir "Esta es una declaración de depuración. x =", x

Entonces, cuando quiero llevar a cabo todas las declaraciones del depuración, cambio la depuración a:

depuración = False

+2

Definir una función lleva a menos tipeo – Casebash

+0

Verdadero. Ciertamente puede poner la instrucción if dentro de una función. Sin embargo, encuentro que la función es un poco más difícil de leer. Y, por supuesto, es menos eficiente ... – vy32

2

utilizar una función printf lugar. Lo siguiente es de Infrequently Answered Python Questions

def printf(format, *args): 
    """Format args with the first argument as format string, and print. 
    If the format is not a string, it is converted to one with str. 
    You must use printf('%s', x) instead of printf(x) if x might 
    contain % or backslash characters.""" 
    print str(format) % args, 

Ahora, cuando se pasa de depuración para la producción, se redefine printf así:

def printf(format, *args): 
    pass 

La ventaja de hacerlo de esta manera, es que si usted tiene que ir Atrás y mantenga el código para agregar características o corregir un error, puede volver a activar printf.

+0

Hay una pequeña sobrecarga en la producción, entonces ... – dangonfast

Cuestiones relacionadas