2009-05-14 11 views
8

Podczas debugowania, chcę wydrukować wszystkie wejścia i wyjścia funkcji (wiem, że potrzebuję lepszego IDE, ale z humorem, to może być użyte do zgłaszania błędów). Tak więc, najlepiej byłoby mieć:Jak napisałbyś @debuggable decorator w python?

@debuggable 
def myfunc(argA,argB,argC): 
    return argB+1 

i używać globalnej zmiennej do włączania i wyłączania debugowania. Nie, nie lubisz też globali, zgadłem.

Najlepszym mogę wymyślić to:

DEBUG = True 

def debuggable(func): 
    if DEBUG: 
     def decorated(*args): 
      print "Entering ",func.func_name 
      print " args ",args 
      ret = func(*args) 
      print ret 
      return ret 
     return decorated 
    else: 
     return func 

@debuggable 
def myfunc(this,that): 
    return this+that 

i działa:

>>> myfunc(1,3) 
Entering myfunc 
    args (1, 3) 
4 

Jak mogę poprawić to?

+0

Jest to dość długi post na blogu na ten temat dekoratorów śledzenia w [Word Aligned] (http://wordaligned.org/articles/echo). –

Odpowiedz

22

Użyj debugera. Poważnie. Dekorowanie każdej funkcji, którą chcesz śledzić, jest złym pomysłem.

Python has a debugger included, więc nie potrzebujesz dobrego IDE.

Jeśli nie chcesz używać debuggera, możesz użyć trace function.

import sys 

@sys.settrace 
def trace_debug(frame, event, arg): 
    if event == 'call': 
     print ("calling %r on line %d, vars: %r" % 
       (frame.f_code.co_name, 
       frame.f_lineno, 
       frame.f_locals)) 
     return trace_debug 
    elif event == "return": 
     print "returning", arg 

def fun1(a, b): 
    return a + b 

print fun1(1, 2) 

która drukuje:

calling 'fun1' on line 14, vars: {'a': 1, 'b': 2} 
returning 3 
3 

jeszcze łatwiej byłoby użyć Winpdb:

To jest niezależna od platformy graficzny debugger GPL Python z obsługą zdalnego debugowania przez sieć, stwardnienie wątki, modyfikacja przestrzeni nazw, wbudowane debugowanie, szyfrowana komunikacja i jest do 20 razy szybsza niż pdb.

Cechy:

  • licencji GPL. Winpdb to darmowe oprogramowanie.
  • Kompatybilny z CPython 2.3 lub nowszym.
  • Kompatybilny z wxPython 2.6 lub nowszym.
  • Platforma niezależna i testowana na systemach Ubuntu Gutsy i Windows XP.
  • Interfejsy użytkownika: rpdb2 jest oparty na konsolach, a winpdb wymaga wxPython 2.6 lub nowszego.

Screenshot http://winpdb.org/images/screenshot_winpdb_small.jpg

6

zgadzam się z nosklo wykorzystaniem debuggera jest znacznie lepiej niż pisanie własnych. Wezwę ulepszenie do twojego kodu. Ale nadal uważam, że powinieneś przestrzegać rad Nosklo.

klas Zastosowanie dekorator, aby Państwa debugger neater:

class Debugger(object): 
    enabled = False 
    def __init__(self, func): 
     self.func = func 

    def __call__(self, *args, **kwargs): 
     if self.enabled: 
      print 'Entering', self.func.func_name 
      print ' args:', args, kwargs 
     return self.func(*args, **kwargs) 

Debugger.enabled = True 

@Debugger 
def myfunc(a, b, c, d): 
    pass 
0

I drugi co nosklo powiedział.

Inną rzeczą jest fakt, że czynność jest nieco niebezpieczne:

b = myfunc(1,3) 

W tym przypadku, „b” jest None, ponieważ funkcja urządzone nic nie wróci.

7

Myślę, że to, czego szukasz, nie jest tak naprawdę dekoratorem debugowania, ale raczej dekoratorem wyrębu.

Używanie Python's logging module może mieć sens, dzięki czemu można uzyskać dokładniejszą kontrolę nad samym rejestrowaniem. Na przykład można by wyprowadzić do pliku w celu późniejszej analizy danych wyjściowych.

Dekorator może wtedy wyglądać mniej więcej tak:

 

import logging 

logger = logging.getLogger('TraceLog') 
# TODO configure logger to write to file/stdout etc, it's level etc 


def logthis(level): 
    def _decorator(fn): 
     def _decorated(*arg,**kwargs): 
      logger.log(level, "calling '%s'(%r,%r)", fn.func_name, arg, kwargs) 
      ret=fn(*arg,**kwargs) 
      logger.log(level, "called '%s'(%r,%r) got return value: %r", fn.func_name, arg, kwargs, ret) 
      return ret 
     return _decorated 
    return _decorator 

@logthis(logging.INFO) 
def myfunc(this,that): 
    return this+that 
 

a następnie, jeśli skonfigurować rejestrator do wyjścia na stderr chcesz zobaczyć:

 

>>> logger.setLevel(logging.INFO) 
>>> handler=logging.StreamHandler() 
>>> logger.addHandler(handler) 
>>> myfunc(1,2) 
calling 'myfunc'((1, 2),{}) 
called 'myfunc'((1, 2),{}) got return value: 3 
 
Powiązane problemy