绘制通话图


12

我正在维护使用python编写的旧代码库。特别是,有一段复杂的代码可以从一个模块调用其他功能,而从其他模块调用其他功能,依此类推。它不是OOP,而只是功能和模块。
每当我调用main函数时,我都试图跟踪流的开始和结束位置,但是我觉得我需要绘制该流,因为我在子调用中迷路了。

让我担心的是,每个函数都在其体内调用多个外部函数以完成其任务并将该值返回给调用者。

我怎么画这个?意味着哪种图表/图形适合于记录这种行为/代码?

因此,我认为绘制UML图和流程图都不有用。通话图,也许吗?


doxygen-将生成呼叫/呼叫者图,我不确定它对python有多少支持。我知道您可以为此编写python代码。
gbjbaanb 2015年

我已经尝试过pycallgraph,但是它太复杂/太深而无法使用它。这是由于我的代码很复杂,因为它混合了纯python和django以及对API url的外部调用。这就是为什么我只想考虑我需要的相关部分而手工绘制它的原因。问题是我不知道要使用哪种图形来全面了解系统
Leonardo 2015年

5
如果这只是为了帮助您理解它,则只需画出自然而然的内容即可。如果要纳入正式文档,您以后可以随时整理一下。
jonrsharpe 2015年

Answers:


9

我认为您在这里寻找的是序列图。这些使您可以可视化各种模块通过使用箭头相互调用的顺序。

构造一个很简单:

  1. 用下面的虚线画您的入门班。
  2. 在呼叫跟踪中绘制下一个类/方法,并在其下方用虚线画出
  3. 用箭头将线连接起来,垂直位于您绘制的最后一个箭头下方
  4. 对跟踪中的所有呼叫重复步骤2-3

假设我们有以下代码要为其创建序列图:

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

我们首先要绘制的是main连接到方法的入口点()long_division。请注意,这会在long_division中创建一个框,表示方法调用的范围。对于这个简单的示例,由于这是唯一的事情,因此该框将是序列图的整个高度。

在此处输入图片说明

现在,我们致电find_largest_fit寻找适合我们工作号码的最大倍数,并将其返回给我们。我们在long_divisionfind_largest_fit另一条方框之间划一条线,以表示函数调用的范围。请注意返回乘数时框如何结束;这是功能范围的结尾!

在此处输入图片说明

重复几次以获得更大的数字,您的图表应如下所示:

在此处输入图片说明

笔记

您可以选择是使用传递的变量名来标记调用,还是仅在记录一种特定情况时才选择其值。您还可以通过调用自身的函数来显示递归。

另外,您可以在此处显示用户并提示他们,并轻松地将其输入到系统中。这是一个相当灵活的系统,我认为您会发现它非常有用!


谢谢,我确实知道序列图,但是对我来说,它更适合oop。就我而言,情况比较混乱,这意味着例如我在多个模块中分布了大约20个功能/助手。我应该指定该函数所属的模块吗?考虑到一些功能也进口过程中改名..
莱昂纳多

1
我要说的是,有多少个模块都没关系-上面的例子也不是。只需命名它们,以便以后可以找到它们,例如ModuleA / function1,ModuleB / Function2等。对于20个函数,它会更大,但绝对不是不可能理解。另一个您可以做的是在函数的最后一次使用之后结束该行的行,并在其下放置另一条函数行以节省图中的水平空间。
Ampt

6

我认为调用图将是最合适的可视化。如果您决定不手动执行此操作,则可以使用一个不错的小工具pyan来对python文件进行静态分析,并可以通过graphviz点文件(可以呈现为图像)生成可视化的调用图。已经有几个分支,但是功能最全的分支似乎是https://github.com/davidfraser/pyan

您只需要在运行命令时指定要处理的所有文件:

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

要么

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

您可以使用“ -n”使图形更整洁,从而删除显示函数定义位置的行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.