Tegn en anropsgraf

Jeg opprettholder en gammel kodebase skrevet i python. Spesielt er det et komplekst stykke kode som fra en modul kaller andre funksjoner fra andre moduler som kaller andre funksjoner og så videre. Det er ikke OOP, bare funksjoner og moduler.
Jeg har prøvd å holde oversikt over hvor strømmen begynner og slutter når som helst jeg kaller hovedfunksjonen, men jeg føler at jeg trenger å tegne dette fordi jeg går tapt i undersamtalene.

Det som bekymrer meg er at hver funksjon kaller flere eksterne funksjoner i kroppen for å fullføre oppgaven og returnere verdien til den som ringer.

Hvordan kan jeg tegne dette? Betydning hva slags diagram / grafikk som passer for å dokumentere denne typen oppførsel / kode?

Så jeg tror ikke det ville være nyttig å tegne et UML-diagram , verken et flytskjema. En samtalediagram, kanskje?

Kommentarer

  • doxygen – vil generere anrops- / anropsgrafer, jeg ' Jeg er ikke sikker på hvor mye støtte den har for python. Jeg vet at du kan dokumentere pythonkode for det.
  • Jeg ' har prøvd pycallgraph, men det ' er bare for komplisert / for dypt til å bruke den. Dette skyldes kompleksiteten i koden min fordi den blander vanlig python med django og ekstern samtale til API-url. Derfor ønsket jeg å tegne det for hånd bare med tanke på den relevante delen jeg trenger. Problemet er at jeg ikke vet ' hva slags graf jeg skal bruke for å ha full forståelse av systemet
  • Hvis dette bare er for å hjelpe deg med å forstå det , bare tegne det som kommer naturlig. Du kan alltid rydde det opp senere hvis det ' går i formell dokumentasjon.

Svar

Jeg tror det du leter etter her er et Sekvensdiagram . Disse lar deg visualisere rekkefølgen som ulike moduler kaller hverandre ved hjelp av pilene.

Å konstruere en er enkel:

  1. Tegn startklassen din med en stiplet linje under den.
  2. Tegn neste klasse / metode i samtalespor med en stiplet linje under den
  3. Koble linjene med en pil, vertikalt plassert under den siste pilen du tegnet
  4. Gjenta trinn 2-3 for alle samtaler i sporet ditt

Eksempel

La oss anta at vi har følgende kode vi vil lage 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") 

Det første vi tegner er inngangspunktet (main) som kobler til metoden long_division Merk at dette skaper en rute i lang_ divisjon, som indikerer omfanget av metodeanropet. For dette enkle eksemplet vil boksen være hele høyden på sekvensdiagrammet vårt på grunn av at dette er det eneste som kjøres.

skriv inn bildebeskrivelse her

Nå ringer vi til find_largest_fit for å finne det største multiplumet som passer innenfor vårt arbeidsnummer , og returnerer den til oss. Vi tegner en linje fra long_division til find_largest_fit med en annen rute for å betegne omfanget for funksjonsanropet. Legg merke til hvordan boksen slutter når multiplikatoren returneres; dette er slutten på det funksjonsomfanget!

skriv inn bildebeskrivelse her

Gjenta et par ganger for et større tall, og diagrammet ditt skal se slik ut:

enter bildebeskrivelse her

Merknader

Du kan velge om du vil merke samtalene med variabelnavnene som er bestått, eller deres verdier hvis du bare vil dokumentere en bestemt sak. Du kan også vise rekursjon med en funksjon som kaller seg selv.

I tillegg kan du vise brukere her inne og be dem om og vise deres input til systemet enkelt nok. Det er et ganske fleksibelt system som jeg tror du vil finne ganske nyttig!

Kommentarer

  • Takk, jeg kjenner sekvensdiagrammet, men det føles for meg at det er mer egnet for oop. I mitt tilfelle er ting litt mer rotete, noe som betyr at jeg for eksempel har rundt 20 funksjoner / hjelpere spredt rundt flere moduler. Ho vil jeg spesifisere modulen som funksjonen tilhører? Tatt i betraktning at noen funksjoner også blir omdøpt under import ..
  • Jeg vil si at det ikke betyr noe hvor mange moduler du har – det ovennevnte eksemplet er ikke noe i det hele tatt heller. Bare navngi dem slik at du kan finne dem senere, ModuleA / function1, ModuleB / Function2 etc. For 20 funksjoner vil den være større, men definitivt ikke umulig å forstå. En annen tror du kan gjøre er å avslutte linjen for en funksjon etter siste bruk og legge en annen funksjonslinje under den for å spare vannrett plass i diagrammet ditt.

Svar

Jeg tror en samtalediagram ville være den mest passende visualiseringen.Hvis du bestemmer deg for ikke å gjøre det for hånd, er det et fint lite verktøy kalt pyan som gjør statisk analyse på en python-fil og kan generere en visualisert samtalediagram ved hjelp av en graphviz-prikk (som kan gjengis til et bilde). Det har vært et par gafler, men den mest fullverdige ser ut til å være https://github.com/davidfraser/pyan .

Du trenger bare å spesifisere alle filene du vil behandle når du kjø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 gjøre grafen renere med «-n» som fjerner linjer som viser hvor en funksjon ble definert.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *