2015-08-23 26 views
8

Chcę, dla celów debugowania, wydrukować coś odnoszącego się do każdej linii wykonanej w metodzie pythona.Python Decorator do drukowania każdej linii wykonanej za pomocą funkcji

Na przykład, jeśli w wierszu było jakieś przypisanie, chcę wydrukować, jaka wartość została przypisana dla tej zmiennej, a jeśli było wywołanie funkcji, chcę wydrukować wartość zwróconą przez funkcję, itp.

tak więc, na przykład, jeśli miałbym użyć dekorator, stosowane na funkcji/metody, takie jak:

@some_decorator 
def testing() : 
    a = 10 
    b = 20 
    c = a + b 
    e = test_function() 

testowanie funkcji po nazwie, należy wydrukować następujące:

a = 10 
b = 20 
c = 30 
e = some_value 

Czy jest jakiś sposób, aby to osiągnąć? Bardziej fundamentalnie, chcę wiedzieć, czy mogę napisać kod, który może przejść przez jakiś inny kod po linii, sprawdzić, jaki rodzaj instrukcji jest, itp. A może lubimy, możemy uzyskać słownik do znajdowania wszystkich zmiennych w klasy, czy mogę uzyskać słownik taki jak struktura danych, aby uzyskać wszystkie instrukcje w funkcji, która jest tak dobra, jak metaprogram może uzyskać.

W związku z tym, szczególnie szukam rozwiązania przy użyciu dekoratorów, ponieważ jestem ciekawy, czy można mieć dekorator, który może przejść całą linię funkcji po linii i ozdobić ją wiersz po linii, , ale wszelkie rozwiązania są Witamy.

Z góry dziękuję.

+4

on współpracować zrobimy to, ale nie znam jednego. Zasadniczo możesz wyodrębnić plik i numer linii z udekorowanej funkcji, ponownie przeczytać funkcję, skompilować ją do AST, wstawić węzły w AST, a następnie skompilować AST i użyć go jako funkcji. Ciekawy projekt. –

+8

Może pomocny będzie moduł ['pdb'] (https://docs.python.org/2/library/pdb.html)? – augurar

+0

@perreal, możesz wyjaśnić swoje podejście bardziej szczegółowo lub podać link, gdzie mogę znaleźć więcej informacji na temat elementów w twoim podejściu, a jeśli to możliwe, zastosować je w moim problemie. dzięki przy okazji dla twojej odpowiedzi – ironstein

Odpowiedz

11

Co powiesz na coś takiego? Czy to działa dla ciebie?

Debug Kontekst:

import sys 

class debug_context(): 
    """ Debug context to trace any function calls inside the context """ 

    def __init__(self, name): 
     self.name = name 

    def __enter__(self): 
     print('Entering Debug Decorated func') 
     # Set the trace function to the trace_calls function 
     # So all events are now traced 
     sys.settrace(self.trace_calls) 

    def __exit__(self, *args, **kwargs): 
     # Stop tracing all events 
     sys.settrace = None 

    def trace_calls(self, frame, event, arg): 
     # We want to only trace our call to the decorated function 
     if event != 'call': 
      return 
     elif frame.f_code.co_name != self.name: 
      return 
     # return the trace function to use when you go into that 
     # function call 
     return self.trace_lines 

    def trace_lines(self, frame, event, arg): 
     # If you want to print local variables each line 
     # keep the check for the event 'line' 
     # If you want to print local variables only on return 
     # check only for the 'return' event 
     if event not in ['line', 'return']: 
      return 
     co = frame.f_code 
     func_name = co.co_name 
     line_no = frame.f_lineno 
     filename = co.co_filename 
     local_vars = frame.f_locals 
     print (' {0} {1} {2} locals: {3}'.format(func_name, 
                event, 
                line_no, 
                local_vars)) 

Debug Dekorator:

def debug_decorator(func): 
    """ Debug decorator to call the function within the debug context """ 
    def decorated_func(*args, **kwargs): 
     with debug_context(func.__name__): 
      return_value = func(*args, **kwargs) 
     return return_value 
    return decorated_func 

Wykorzystanie

@debug_decorator 
def testing() : 
    a = 10 
    b = 20 
    c = a + b 

testing() 

Wyjście

########################################################### 
#output: 
# Entering Debug Decorated func 
#  testing line 44 locals: {} 
#  testing line 45 locals: {'a': 10} 
#  testing line 46 locals: {'a': 10, 'b': 20} 
#  testing return 46 locals: {'a': 10, 'b': 20, 'c': 30} 
########################################################### 
+0

To jest bardzo przydatne, powinno to być oznaczone jako poprawna odpowiedź. – DimmuR

+0

Jak rozszerzyć tę metodę dla klas? – neok

+0

Niesamowite, zastanawiam się, dlaczego jest tak mało upvotes tutaj :( –