Desenhe um gráfico de chamada

Estou mantendo uma base de código antiga escrita em python. Em particular, há um trecho complexo de código que a partir de um módulo chama outras funções de outros módulos que chamam outras funções e assim por diante. Não é OOP, apenas funções e módulos.
Eu tentei acompanhar onde o fluxo começa e termina sempre que chamo a função principal, mas sinto que preciso desenhar isso porque estou me perdendo nas subchamadas.

O que me preocupa é que cada função chama várias funções externas dentro de seu corpo para completar sua tarefa e retornar o valor ao chamador.

Como posso desenhar isso? O que significa que tipo de gráfico / gráfico seria apropriado para documentar esse tipo de comportamento / código?

Então, não acho que seria útil desenhar um diagrama UML , nem um fluxograma. Um gráfico de chamadas, talvez?

Comentários

  • doxygen – gerará gráficos de chamadas / chamadores, I ' Não tenho certeza de quanto suporte ele tem para python. Eu sei que você pode documentar o código Python para ele.
  • Eu ' tentei o pycallgraph, mas ' também complicado / muito profundo para usá-lo. Isso se deve à complexidade do meu código, pois ele mistura python simples com django e chamada externa para URL da API. É por isso que quis desenhá-lo à mão levando em consideração apenas a parte relevante de que preciso. O problema é que eu não ' não sei que tipo de gráfico usar para ter um entendimento completo do sistema
  • Se for apenas para ajudá-lo a entendê-lo , apenas desenhe o que vier naturalmente. Você sempre pode arrumar mais tarde se ' estiver indo para a documentação formal.

Resposta

Acho que o que você está procurando aqui é um Diagrama de sequência . Eles permitem que você visualize a ordem em que vários módulos chamam um ao outro através do uso de setas.

Construir uma é simples:

  1. Desenhe sua classe inicial com uma linha pontilhada abaixo dela.
  2. Desenhe a próxima classe / método no rastreamento de chamada com uma linha pontilhada abaixo dela
  3. Conecte as linhas com uma seta, posicionada verticalmente abaixo da última seta que você desenhou
  4. Repita as etapas 2-3 para todas as chamadas em seu rastreamento

Exemplo

Vamos supor que temos o seguinte código para o qual queremos criar um diagrama de sequência:

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

A primeira coisa que desenharemos é o ponto de entrada (main) conectando-se ao método long_division . Observe que isso cria uma caixa em long_ divisão, significando o escopo da chamada do método. Para este exemplo simples, a caixa terá toda a altura do nosso diagrama de sequência devido ao fato de que esta é a única coisa executada.

insira a descrição da imagem aqui

Agora chamamos find_largest_fit para encontrar o maior múltiplo que se encaixe em nosso número de trabalho , e nos devolve. Desenhamos uma linha de long_division a find_largest_fit com outra caixa para indicar o escopo da chamada de função. Observe como a caixa termina quando o multiplicador é retornado; este é o fim do escopo das funções!

insira a descrição da imagem aqui

Repita algumas vezes para um número maior e seu gráfico deve ser semelhante a este:

digite descrição da imagem aqui

Notas

Você pode escolher se deseja rotular as chamadas com os nomes de variáveis passados ou seus valores, se apenas desejar documentar um caso específico. Você também pode mostrar a recursão com uma função chamando a si mesma.

Além disso, você pode mostrar os usuários aqui e solicitá-los e mostrar sua entrada no sistema com bastante facilidade. É um sistema bastante flexível que acho que você achará bastante útil!

Comentários

  • Obrigado, eu conheço o diagrama de sequência, mas parece-me que é mais adequado para oop. No meu caso, as coisas estão um pouco mais confusas, o que significa que, por exemplo, tenho cerca de 20 funções / auxiliares espalhados por vários módulos. Como eu especificaria o módulo ao qual a função pertence? Considerando que algumas funções também são renomeadas durante as importações …
  • Eu diria que não importa quantos módulos você tem – o exemplo acima também não é oop. Apenas nomeie-os para que você possa encontrá-los mais tarde, MóduloA / função1, MóduloB / Função2 etc. Para 20 funções, será maior, mas definitivamente não impossível de entender. Outra coisa que você pode fazer é terminar a linha de uma função após seu último uso e colocar outra linha de funções abaixo dela para economizar espaço horizontal em seu diagrama.

Resposta

Acho que um gráfico de chamadas seria a visualização mais apropriada.Se você decidir não fazer isso manualmente, existe uma pequena ferramenta agradável chamada pyan que faz análise estática em um arquivo python e pode gerar um gráfico de chamada visualizado por meio de um ponto graphviz (que pode ser renderizado em uma imagem). Existem alguns garfos, mas o mais completo parece ser https://github.com/davidfraser/pyan .

Você só precisa especificar todos os arquivos que deseja processar ao executar o comando:

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

ou

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

Você pode tornar o gráfico mais limpo com o “-n” que remove o linhas mostrando onde uma função foi definida.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *