Tegn en opkaldsgraf

Jeg opretholder en gammel kodebase skrevet i python. Især er der et komplekst stykke kode, der fra et modul kalder andre funktioner fra andre moduler, der kalder andre funktioner osv. Det er ikke OOP, kun funktioner og moduler.
Jeg har prøvet at holde styr på, hvor strømmen begynder og slutter når som helst, jeg kalder på hovedfunktionen, men jeg føler, at jeg har brug for at tegne dette fordi jeg går vild i underopkaldene.

Hvad der bekymrer mig er, at hver funktion kalder flere eksterne funktioner i deres krop for at fuldføre deres opgave og returnere værdien til den, der ringer op.

Hvordan kan jeg tegne dette? Betydning hvilken slags diagram / grafik ville være passende at dokumentere denne form for adfærd / kode?

Så jeg tror ikke, det ville være nyttigt at tegne et UML-diagram , hverken et rutediagram. En opkaldsgraf, måske?

Kommentarer

  • doxygen – genererer opkalds- / opkaldsgrafer, jeg ' Jeg er ikke sikker på, hvor meget støtte den har til python. Jeg ved, du kan dokumentere pythonkode til det.
  • Jeg ' har prøvet pycallgraph, men det ' er bare også kompliceret / for dybt til at bruge det. Dette skyldes kompleksiteten af min kode, fordi den blander almindelig python med django og eksternt opkald til API-url. Derfor ville jeg kun tegne det i hånden under hensyntagen til den relevante del, jeg har brug for. Problemet er, at jeg ikke ' ikke ved, hvilken slags graf jeg skal bruge til at få en fuld forståelse af systemet
  • Hvis dette bare er for at hjælpe dig med at forstå det , tegn bare hvad der kommer naturligt. Du kan altid rydde det op senere, hvis det ' går ind i formel dokumentation.

Svar

Jeg synes, det du leder efter her er et Sekvensdiagram . Disse giver dig mulighed for at visualisere rækkefølgen, som forskellige moduler kalder på hinanden ved hjælp af pile.

At konstruere en er enkel:

  1. Tegn din startklasse med en stiplet linje under den.
  2. Tegn den næste klasse / metode i opkaldssporingen med en stiplet linje nedenunder
  3. Forbind linjerne med en pil, lodret placeret under den sidste pil, du tegnede
  4. Gentag trin 2-3 for alle opkald i dit spor

Eksempel

Lad os antage, at vi har følgende kode, vi vil oprette et sekvensdiagram for:

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") 

Den første ting, vi tegner, er indgangspunktet (main), der forbinder metoden long_division Bemærk, at dette opretter et felt i lang_ division, der angiver omfanget af metodekaldet. For dette enkle eksempel vil feltet være hele højden af vores sekvensdiagram på grund af det faktum, at dette er det eneste, der køres.

indtast billedbeskrivelse her

Nu ringer vi til find_largest_fit for at finde det største multiplum, der passer inden for vores arbejdsnummer og returnerer det til os. Vi tegner en linje fra long_division til find_largest_fit med et andet felt for at betegne omfanget af funktionsopkaldet. Bemærk, hvordan feltet slutter, når multiplikatoren returneres; dette er slutningen på dette funktionsomfang!

indtast billedbeskrivelse her

Gentag et par gange for et større tal, og dit diagram skal se sådan ud:

indtast billedbeskrivelse her

Noter

Du kan vælge, om du vil mærke opkaldene med de forbundne variabelnavne eller deres værdier, hvis du kun vil dokumentere en bestemt sag. Du kan også vise rekursion med en funktion, der kalder sig selv.

Derudover kan du vise brugere herinde og bede dem om og vise deres input til systemet let nok. Det er et ret fleksibelt system, som jeg synes, du finder ret nyttigt!

Kommentarer

  • Tak, jeg kender sekvensdiagrammet, men det føles for mig, at det er mere egnet til oop. I mit tilfælde er tingene lidt mere rodet, hvilket betyder at jeg for eksempel har omkring 20 funktioner / hjælpere spredt rundt i flere moduler. Ho ville jeg specificere det modul, som funktionen tilhører? I betragtning af at nogle funktioner også omdøbes under import ..
  • Jeg vil sige, at det ikke betyder noget, hvor mange moduler du har – ovenstående eksempel er slet ikke åbent. Bare navngiv dem, så du kan finde dem senere, ModuleA / function1, ModuleB / Function2 osv. For 20 funktioner bliver det større, men bestemt ikke umuligt at forstå. En anden tænkning du kan gøre er at afslutte linjen for en funktion efter dens sidste brug og placere en anden funktionslinje under den for at spare vandret plads i dit diagram.

Svar

Jeg tror, at en opkaldsgraf ville være den mest passende visualisering.Hvis du beslutter dig for ikke at gøre det i hånden, er der “et dejligt lille værktøj kaldet pyan, der udfører statisk analyse på en pythonfil og kan generere en visualiseret opkaldsgraf ved hjælp af en graphviz-prik fil (som kan gengives til et billede). Der har været et par gafler, men den mest fuldt udstyrede ser ud til at være https://github.com/davidfraser/pyan .

Du skal bare angive alle de filer, du vil behandle, når du kører kommandoen:

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

eller

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

Du kan gøre grafen renere med “-n”, som fjerner linjer, der viser, hvor en funktion blev defineret.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *