2009-10-24 15 views
11

Czasami zostawiam debugowanie instrukcji drukowania w moim projekcie i trudno jest go znaleźć. Czy jest jakiś sposób, aby dowiedzieć się, która linia drukuje coś w szczególności?Wyszukiwanie instrukcji drukowania w języku Python

Sidenote

Wydaje się, że poszukiwania inteligentnych może rozwiązać większość przypadków. W Pydev (i innych IDE) dostępna jest funkcja wyszukiwania, która umożliwia przeszukiwanie wszystkich plików w projekcie. Oczywiście podobny efekt można uzyskać, używając grep z flagą -rn, ale zamiast bezpośrednich linków otrzymujesz tylko numery linii.

"print (" działa znacznie lepiej w moim kodzie i często jest dodatkowy tekst w poleceniu print, które można wyszukać za pomocą wyrażenia regularnego. Najtrudniejszy przypadek ma miejsce, gdy masz już napisany print (x), chociaż to mogą być wyszukiwane wyrażenie regularne, gdzie wartość wewnątrz X nie rozpoczęcia lub zakończenia cytatami

+0

Jaki edytor tekstu i system operacyjny ...? –

+0

Używanie Pydev'a w Eclipse – Casebash

+0

Ustawienie tracefunc uruchomi go dla wszystkich połączeń, bez względu na to, jak zostały napisane. – Geo

Odpowiedz

27

Pytasz o rozwiązania statyczne. Oto dynamiczny. Załóżmy, że uruchamiasz kod i widzisz błędny wydruk lub piszesz do sys.stdout i chcesz wiedzieć, skąd pochodzi. Można zastąpić sys.stdout i pozwól pomocą wyjątek Traceback Ci:

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

Na coś bardziej wyrafinowanego, zastąpić „sys.stdout” z czegoś, co raportuje, gdzie znajduje się instrukcja print. Użyję traceback.print_stack(), aby pokazać pełny stos, ale możesz zrobić inne rzeczy, takie jak użycie sys._getframe(), aby wyszukać jeden poziom stosu, aby uzyskać numer linii i nazwę pliku.

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

Oto wynik

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) 

Jeśli pójdziesz tą drogą, patrz także moduł „linecache”, którego można użyć, aby wydrukować zawartość wiersza. Zapoznaj się z implementacją pliku traceback.print_stack, aby dowiedzieć się, jak to zrobić.

+0

Dzięki, to jest geniusz! – Casebash

+0

To jest świetna odpowiedź. Dzięki za udostępnienie! –

+0

Proste i genialne! –

4

Użyj grep (dzięki BecomingGuro!):

grep -rn print .

+0

Powodzenia w bibliotekach stron trzecich, frameworkach javascript, plikach binarnych i innych szczegółach – dangonfast

1

Korzystanie grep z misternie skonstruowanej regex (robi nie zaczynać się lub kończyć cudzysłowem) wydaje się być twoim najlepszym zakładem

+0

Naprawdę powinienem używać wyrażeń regularnych przeszukując więcej. Jednak, jak wspomniano powyżej, są pewne przypadki, które nie obejmują – Casebash

+0

"nie zaczyna się ani nie kończy cytatami" - to jest genialna sztuczka. – Casebash

+0

co jest nie tak z poszukiwaniem "print"? oh czekać ... czy to sprytne wyrażenie regularne? – hasen

5

This article może okazać się bardzo wartościowy w tym zakresie. Poszukaj zdarzeń line i wypakuj nazwę metody z ramki (jeśli dobrze pamiętam). Więcej informacji można znaleźć: here

+0

Wow, to jest po prostu niesamowite. Mogę sobie wyobrazić kilka fajnych hacków, takich jak dodanie ## na końcu każdej linii, którą chcesz śledzić. Może to być powolne, ale możliwe byłoby napisanie wersji, która buforuje wywołania, a więc każda linia musi być sprawdzona tylko raz – Casebash

+0

Schludny element tutaj, ale uważaj, aby go użyć do stworzenia całkowicie niemożliwego do pomylenia kodu ... – vy32

+0

Myślę, że jest to głównie do debugowania – Casebash

2

Najprostszym sposobem byłoby użycie funkcji "debug_print" zamiast zwykłego "print".

W ten sposób możesz po prostu przedefiniować funkcję i upewnić się, że nie przegapiłeś jednego ... i nadal masz je pod ręką, jeśli potrzebujesz ponownie debugować ten kod, zamiast edytować kod za każdym razem.

(Tak pozostawiając połączeń debug_print można zjeść wydajność: po prostu usunąć je, gdy jest to przypadek)

Spotting „debug tylko” oświadczenia w kodzie jest bardzo dobry powód, aby zrobić diff przed comitting żadnego kodu w twoim systemie kontroli wersji! (wiedząc, co umieścić w komentarzach do commitowania, jest to drugi dobry powód, żeby to zrobić!)

+0

Problem polega na tym, że to wymaga więcej wysiłku, aby pisać i spowolnić debugowanie. Może powinienem zdefiniować moje zdanie jako _p – Casebash

+1

Czy nie lepiej byłoby zamiast tego użyć modułu 'logging'? Jeśli dobrze pamiętam, można go dezaktywować, gdy go nie potrzebujesz (abyś nie stracił wydajności, gdy nie potrzebujesz). – Geo

+0

Zgadzam się z Geo, użycie modułu rejestrowania byłoby znacznie czystsze, do czego zostało stworzone. – RedGlyph

0

To prawdopodobnie nie odpowiada bezpośrednio na twoje pytanie, ale możesz uciec z tonami instrukcji drukowania, jeśli używasz pdb (python debugger) w sposób na efektywne debugowanie i pisanie kodu.

Wiem, że to działa, ponieważ w 99% czasu zwyczajnie nie chcesz drukować, ale chcesz ustawić punkt przerwania i sprawdzić, jakie są zmienne i jak daleko osiągnął program.

HTH

+0

Tak naprawdę używam debuggera Pydev'a i faktycznie można wyświetlić zmienne/wyrażenia za pomocą myszy/selekcji, która jest całkiem fajna – Casebash

0

I zwykle to zrobić w moim kodu:

(u góry):

debug=True 

(później)

jeśli debug : print "To jest instrukcja debugowania x =", x

Wtedy, gdy chcę wyjąć wszystkie oświadczenia debugowania, zmienić debug do:

debug = false

+2

Definiowanie funkcji prowadzi do mniejszego pisania – Casebash

+0

Prawda. Możesz oczywiście umieścić instrukcję if wewnątrz funkcji. Uważam, że funkcja jest nieco trudniejsza do odczytania. I, oczywiście, jest to mniej wydajne ... – vy32

2

użyć funkcji printf zamiast. Poniżej znajduje od 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, 

Teraz, po przeniesieniu z debugowania do produkcji, należy przedefiniować printf tak:

def printf(format, *args): 
    pass 

Zaletą robi to w ten sposób, że jeśli trzeba iść wróć i zachowaj kod, aby dodać funkcje lub naprawić błąd, możesz ponownie włączyć printf.

+0

W produkcji jest małe obciążenie ... – dangonfast

Powiązane problemy