2016-12-27 3 views
1

Wie debugge ich Code, der Generatoren und Iteratoren verwendet? Ich fand, dass das Hinzufügen einer for Schleife mit print Anweisungen den Generator/Iterator verbraucht und daher den Rest des Codes durchbricht. Ist es möglich, den "Inhalt" eines Generators/Iterators zu prüfen, ohne die Elemente zu verbrauchen?Debug-Generatoren und Iteratoren

Genauer gesagt, ich habe so etwas wie dies:

result = map(func, x) 

Jetzt will ich sehen, was result ist. Ich möchte auch den zurückgegebenen Wert sehen, indem ich eine Funktion für jedes Element in result anwende. In meinem eigentlichen Code, erhalte ich das Element in result die den Minimalwert dieser Funktion gibt:

best = min(result, key=my_key) 

Jetzt min() ist sehr praktisch, aber ich bin immer falsches Verhalten und müssen herausfinden, warum. Welche Tools kann ich verwenden, um so etwas zu debuggen?

p.s. Ich benutze PyCharm. Ich bin ziemlich zufrieden mit dem interaktiven Debugger, kann aber immer noch nicht herausfinden, wie man alles sieht, was hier vor sich geht.

Antwort

2

Wenn Sie die Werte der Funktionsargumente und die zurückgegebenen Werte drucken möchten, können Sie einen Wrapper verwenden, der die ursprüngliche Funktion umschließt und die in func oder my_key übergebenen Werte und deren Rückgabewerte ausgibt. So etwas wie

def debug_func(func): 
    @functools.wraps(func) 
    def wrapper(*a, **kw): 
     print('Arguments', a, kw) 
     rv = func(*a, **kw) 
     print('Return value', repr(rv)) 
     return rv 
    return wrapper 

Ein Anwendungsbeispiel:

>>> list(map(debug_func(len), ['foo', 'bar', 'foobar'])) 
Arguments ('foo',) {} 
Return value 3 
Arguments ('bar',) {} 
Return value 3 
Arguments ('foobar',) {} 
Return value 6 
[3, 3, 6] 

Oder

>>> min(['foo', 'bar', 'foobar'], keydebug_func(len)) 
Arguments ('foo',) {} 
Return value 3 
Arguments ('bar',) {} 
Return value 3 
Arguments ('foobar',) {} 
Return value 6 
'foo' 

ähnlicher Ansatz für Iteratoren auch verwendet werden könnte:

def debug_iter(iterator): 
    while True: 
     value = next(iterator) 
     print('Iterator yielded', repr(value)) 
     yield value 

Verbrauch:

>>> [i for i in debug_iter(i ** 2 for i in range(5)) if i % 2] 
Iterator yielded 0 
Iterator yielded 1 
Iterator yielded 4 
Iterator yielded 9 
Iterator yielded 16 
[1, 9]