Desenhar um gráfico de chamada


11

Estou mantendo uma base de código antiga escrita em python. Em particular, há um pedaço complexo de código que, 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.
Tentei acompanhar onde o fluxo começa e termina a qualquer momento que chamo a função principal, mas sinto que preciso desenhar isso porque estou me perdendo nas sub-chamadas.

O que me preocupa é que cada função chama várias funções externas em seu corpo para concluir sua tarefa e devolver o valor ao chamador.

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

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


doxygen - irá gerar gráficos de chamada / chamada, não tenho certeza de quanto suporte ele tem para python. Eu sei que você pode documentar o código python para ele.
Gbjbaanb

Eu tentei o pycallgraph, mas é muito complicado / muito profundo para usá-lo. Isso se deve à complexidade do meu código, porque combina python simples com django e chamada externa para o URL da API. É por isso que eu queria desenhá-lo manualmente, levando em consideração a parte relevante de que eu precisava. O problema é que eu não sei que tipo de gráfico para usar para ter uma compreensão completa do sistema
Leonardo

5
Se isso é apenas para ajudá-lo a entender, basta desenhar o que vier naturalmente. Você sempre pode arrumar mais tarde, se estiver entrando em documentação formal.
precisa saber é o seguinte

Respostas:


9

Eu acho que o que você está procurando aqui é um diagrama de sequência . Isso permite que você visualize a ordem em que vários módulos se chamam através do uso de setas.

Construir um é 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 desse
  3. Conecte as linhas com uma seta, posicionada verticalmente abaixo da última seta que você desenhou
  4. Repita as etapas 2 a 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) conectado ao método long_division. Observe que isso cria uma caixa em long_division, 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 essa é a única coisa executada.

insira a descrição da imagem aqui

Agora, ligamos find_largest_fitpara encontrar o maior múltiplo que se encaixa no nosso número de trabalho e o devolve. Nós desenhamos uma linha de long_divisionpara find_largest_fitcom outra caixa para indicar o escopo da chamada de função. Observe como a caixa termina quando o multiplicador é retornado; este é o fim desse escopo de funções!

insira a descrição da imagem aqui

Repita algumas vezes para um número maior e seu gráfico deve ficar assim:

insira a 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 desejar apenas documentar um caso específico. Você também pode mostrar recursão com uma função que se chama.

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 eu acho que você achará bastante útil!


Obrigado, eu conheço o diagrama de sequência, mas sinto que é mais adequado para oop. No meu caso, as coisas são um pouco mais complicadas, 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 renomeados durante importações ..
Leonardo

1
Eu diria que não importa quantos módulos você tenha - o exemplo acima também não está disponível. Apenas nomeie-os para que você possa encontrá-los mais tarde, ModuleA / function1, ModuleB / Function2 etc. Para 20 funções, será maior, mas definitivamente não é impossível de entender. Outro pensamento que você pode fazer é encerrar 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.
Ampt

5

Eu acho que um gráfico de chamada seria a visualização mais apropriada. Se você decidir não fazer isso manualmente, há uma pequena ferramenta chamada pyananálise estática em um arquivo python e pode gerar um gráfico de chamada visualizado por meio de um arquivo de ponto de gráfico (que pode ser renderizado em uma imagem). Houve 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 as linhas que mostram onde uma função foi definida.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.