Desenați un grafic de apel

I „m mențin o bază de cod veche scrisă în python. În special există o bucată de cod complexă care dintr-un modul apelează alte funcții de la alte module care apelează alte funcții și așa mai departe. Nu este OOP, doar funcții și module.
Am încercat să urmăresc de unde începe și se termină fluxul oricând apelez funcția principală, dar simt că trebuie să desenez asta pentru că mă pierd în apeluri secundare.

Ceea ce mă preocupă este că fiecare funcție apelează mai multe funcții externe din corpul lor pentru a-și finaliza sarcina și a returna valoarea către apelant.

Cum pot desena acest lucru? Adică ce tip de diagramă / grafic ar fi adecvat pentru a documenta acest tip de comportament / cod?

Deci, nu cred că ar fi util să desenăm o diagramă UML , nici o diagramă de flux. Un grafic de apel, poate?

Comentarii

  • doxygen – va genera grafice de apel / apelant, I ' Nu sunt sigur cât de mult suport are Python. Știu că puteți documenta codul Python pentru acesta.
  • Am ' am încercat pycallgraph, dar ' este prea complicat / prea profund pentru a-l folosi. Acest lucru se datorează complexității codului meu, deoarece amestecă Python simplu cu django și apel extern la adresa URL URL. De aceea am vrut să-l desenez manual doar ținând cont de partea relevantă de care am nevoie. Problema este că nu ' nu știu ce tip de grafic să folosesc pentru a avea o înțelegere completă a sistemului
  • Dacă acest lucru este doar pentru a vă ajuta să îl înțelegeți , doar desenează orice vine natural. Puteți oricând să-l ordonați mai târziu dacă ' intră în documentația formală.

Răspuns

Cred că ceea ce căutați aici este o Diagramă de secvențe . Acestea vă permit să vizualizați ordinea în care apelează diferite module reciproc prin utilizarea săgeților.

Construirea uneia este simplă:

  1. Desenați clasa de început cu o linie punctată sub ea.
  2. Desenați următoarea clasă / metodă în urmărirea apelului cu o linie punctată dedesubt care
  3. Conectați liniile cu o săgeată, poziționată vertical sub ultima săgeată pe care ați desenat-o
  4. Repetați pașii 2-3 pentru toate apelurile în urma dvs.

Exemplu

Să presupunem că avem următorul cod pentru care dorim să creăm o diagramă de ordine pentru:

def long_division(quotient, divisor): solution = "" remainder = quotient working = "" while len(remainder) > 0: working += remainder[0] remainder = remainder[1:] multiplier = find_largest_fit(working, divisor) solution += multiplier working = calculate_remainder(working, multiplier, divisor) print solution def calculate_remainder(working, multiplier, divisor): cur_len = len(working) int_rem = int(working) - (int(multiplier) * int (divisor)) return "%*d" % (cur_len, int_rem) def find_largest_fit(quotient, divisor): if int(divisor) == 0: return "0" i = 0 while i <= 10: if (int(divisor) * i) > int(quotient): return str(i - 1) else: i += 1 if __name__ == "__main__": long_division("645", "5") 

Primul lucru pe care îl vom desena este punctul de intrare (main) care se conectează la metoda long_division Rețineți că acest lucru creează o casetă în lung_ diviziune, semnificând sfera apelului metodei. Pentru acest exemplu simplu, caseta va fi întreaga înălțime a diagramei noastre de secvență datorită faptului că acesta este singurul lucru executat.

introduceți descrierea imaginii aici

Acum apelăm la find_largest_fit pentru a găsi cel mai mare multiplu care se potrivește numărului nostru de lucru , și ni-l returnează. Tragem o linie de la long_division la find_largest_fit cu o altă casetă pentru a semnifica domeniul de aplicare al apelului de funcție. Rețineți cum se termină caseta la întoarcerea multiplicatorului; acesta este sfârșitul acestui domeniu de funcții!

introduceți descrierea imaginii aici

Repetați de câteva ori pentru un număr mai mare și diagrama dvs. ar trebui să arate cam așa:

introduceți descrierea imaginii aici

Note

Puteți alege dacă doriți să etichetați apelurile cu numele variabilelor trecute sau valorile acestora dacă doriți doar să documentați un caz specific. De asemenea, puteți afișa recursivitatea cu o funcție care se numește.

În plus, puteți afișa utilizatorii aici și le puteți solicita și afișa intrarea lor în sistem suficient de ușor. „Este un sistem destul de flexibil pe care cred că îl veți găsi destul de util!

Comentarii

  • Mulțumesc, știu diagrama de secvență, dar pentru mine este mai potrivit pentru oop. În cazul meu, lucrurile sunt puțin mai dezordonate, ceea ce înseamnă că, de exemplu, am în jur de 20 de funcții / ajutoare răspândite în mai multe module. Cum aș specifica modulul căruia îi aparține funcția? Având în vedere că unele funcții sunt, de asemenea, redenumite în timpul importurilor ..
  • Aș spune că nu contează câte module aveți – nici exemplul de mai sus nu este deloc. Numiți-le doar pentru a le putea găsi mai târziu, ModuleA / function1, ModuleB / Function2 etc. Pentru 20 de funcții va fi mai mare, dar cu siguranță nu este imposibil de înțeles. O altă idee pe care o puteți face este să încheiați linia pentru o funcție după ultima sa utilizare și să puneți o altă linie de funcții sub ea pentru a economisi spațiu orizontal în diagramă.

Răspuns

Cred că un grafic de apel ar fi cea mai potrivită vizualizare.Dacă decideți să nu o faceți manual, există un mic instrument numit pyan care face analize statice pe un fișier Python și poate genera un grafic de apel vizualizat prin intermediul unui punct graphviz fișier (care poate fi redat unei imagini). Au existat câteva furci, dar cea mai completă funcție pare să fie https://github.com/davidfraser/pyan .

Trebuie doar să specificați toate fișierele pe care doriți să le prelucrați când executați comanda:

python ~/bin/pyan.py --dot a.py b.py c.py -n > pyan.dot; dot -Tpng -opyan.png pyan.dot

sau

python ~/bin/pyan.py --dot $(find . -name "*.py") -n > pyan.dot; dot -Tpng -opyan.png pyan.dot

Puteți face graficul mai curat cu „-n” care elimină linii care arată unde a fost definită o funcție.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *