2009-11-07 18 views
19

Uwielbiam być w stanie zmodyfikować argumenty wysyłane do funkcji, za pomocą settrace jak:Jakie fajne sztuczki można zrobić za pomocą sys.settrace?

import sys 

def trace_func(frame,event,arg): 
    value = frame.f_locals["a"] 
    if value % 2 == 0: 
     value += 1 
     frame.f_locals["a"] = value 

def f(a): 
    print a 

if __name__ == "__main__": 
    sys.settrace(trace_func) 
    for i in range(0,5): 
     f(i) 

I to wypisze:

1 
1 
3 
3 
5 

Jakie inne fajne rzeczy można zrobić za pomocą settrace ?

+4

nie jest to zła – Casebash

+0

Tak, ale w dobry sposób istnieje :) – Geo

Odpowiedz

23

Zdecydowanie polecam przeciwko nadużywaniu settrace. Zakładam, że rozumiesz te rzeczy, ale inni idą później, może nie. Istnieje kilka powodów:

  1. Settrace to narzędzie bardzo tępe. Przykład OP jest prosty, ale praktycznie nie ma możliwości rozszerzenia go na rzeczywisty system.

  2. To tajemnicze. Każdy, kto przyjrzy się twojemu kodowi, będzie kompletnie zaskoczony, dlaczego robi to, co robi.

  3. Jest powolny. Wywoływanie funkcji Pythona dla każdej linii Pythona spowoduje spowolnienie programu o wiele wielokrotności.

  4. Jest to zwykle niepotrzebne. Oryginalny przykład tutaj mógłby zostać zrealizowany na kilka innych sposobów (zmodyfikuj funkcję, zawiń funkcję w dekoratorze, wywołaj ją za pomocą innej funkcji itd.), Z których każda byłaby lepsza niż settrace.

  5. Trudno jest dobrze. W oryginalnym przykładzie, gdybyś nie zadzwonił bezpośrednio do f, ale zamiast tego nazywał się g, który nazwał f, twoja funkcja śledzenia nie wykonałaby swojej pracy, ponieważ zwróciłeś None z funkcji trace, więc jest ona wywoływana tylko raz, a następnie zapomniana.

  6. Utrzyma inne narzędzia do pracy. Ten program nie będzie debuggować (ponieważ debuggery używają settrace), nie będzie można go prześledzić, nie będzie można zmierzyć jego zasięgu kodu, itp. Częściowo wynika to z braku przewidywania ze strony implementatorów Python: oni dał nam settrace, ale bez gettrace, więc trudno jest mieć dwie funkcje śledzenia, które działają razem.

Funkcje śledzenia umożliwiają tworzenie fajnych hacków. Fajnie jest móc go nadużywać, ale nie używaj go do prawdziwych rzeczy. Jeśli zabrzmię hectoring, przepraszam, ale zostało to zrobione w prawdziwym kodzie i to jest ból. Na przykład, DecoratorTools wykorzystuje funkcję śledzenia wykonać magiczną wyczyn dokonywania tej pracy składni w Pythonie 2.3:

# Method decorator example 
from peak.util.decorators import decorate 

class Demo1(object): 
    decorate(classmethod) # equivalent to @classmethod 
    def example(cls): 
     print "hello from", cls 

Zgrabny hack, ale niestety, to znaczy, że każdy kod, który używany DecoratorTools nie będzie działać z zakresu .py (lub, jak sądzę, debuggery). Niezbyt dobry kompromis, jeśli mnie poprosisz. Zmieniłem cover.py, aby zapewnić tryb, który pozwala mu pracować z DecoratorTools, ale szkoda, że ​​nie musiałem.

Nawet kod w standardowej bibliotece czasami źle to robi. Pyexpat postanowił być inny niż każdy inny moduł rozszerzenia i wywoływał funkcję trace tak, jakby był to kod Pythona. Szkoda, że ​​oni did a bad job of it.

</rant>

+0

sys.gettrace od Pythonie 2.6 (http://docs.python.org/library/sys.html#sys.gettrace), ale ze względu na sposób projektowania settrace, gdy program obsługi zwraca nową funkcję obsługi dla każdego połączenia, tak naprawdę nie pomaga. Całkowicie zgadzam się z twoimi głównymi punktami - settrace nie nadaje się do niczego innego niż (wolne) debugowanie. –

+0

Ta odpowiedź została napisana w 2009 roku i powinienem powiedzieć, że nie wszystkie punkty podniesione przez autora już obowiązują. sys.settrace() i inne debuggery ** mogą ** współistnieć w zależności od implementacji (np. ipdb.set_trace()). Również tam ** jest ** funkcja gettrace() zaimplementowana ... Również w zależności od implementacji twój kod niekoniecznie musi działać "wolno przez wiele wielokrotności". To nigdy nie będzie szybsze, tak, ale to wciąż nadmierna generalizacja. – aarslan

+0

@aarslan, który nie jest nadmierną generacją: dodawanie kodu jest _always_ wolniejsze. Ponadto narzędzia do debugowania nie są tworzone dla wydajności, ale dla debugowania. Wreszcie używanie narzędzi do debugowania jako kodu funkcjonalnego jest jedną z najgorszych praktyk, jakie kiedykolwiek spotkałem. – Tim

9

Oczywiście pokrycie kodu jest realizowane za pomocą funkcji śledzenia. Jeszcze jedną fajną rzeczą, której wcześniej nie mieliśmy, jest pomiar zasięgu gałęzi, a to ładnie się zbliża, zostanie wydane w wersji alfa coverage.py.

Tak na przykład rozważyć tę funkcję:

def foo(x): 
    if x: 
     y = 10 
    return y 

jeśli przetestować go z tej rozmowy:

assert foo(1) == 10 

następnie pokrycie instrukcji powie, że wszystkie linie funkcji zostały wykonane. Ale oczywiście w tej funkcji jest prosty problem: wywołanie go za pomocą 0 powoduje wywołanie UnboundLocalError.

Pomiary oddziału informują o tym, że w kodzie znajduje się odgałęzienie, które nie jest w pełni wykorzystywane, ponieważ tylko jedna odnoga gałęzi jest kiedykolwiek brana.

17

Zrobiłem moduł o nazwie pycallgraph który generuje wykresy połączeń przy użyciu sys.settrace().

+0

Nie widzę wartości dodanej w porównaniu do 'gprof2dot', który generuje dokładnie te same wykresy od lat (od 2007-03-30 dokładnie zobacz [projekt GitHub] (https://github.com/jrfonseca/gprof2dot)) , z wyjątkiem tego, że dodaje informacje o czasie dotyczące każdej wywoływanej funkcji (czas własny, łączny czas, liczba połączeń). Dobra robota. – Tim

Powiązane problemy