Vẽ biểu đồ cuộc gọi


11

Tôi đang duy trì một cơ sở mã cũ được viết bằng python. Cụ thể, có một đoạn mã phức tạp mà từ một mô-đun gọi các chức năng khác từ các mô-đun khác gọi các chức năng khác, v.v. Nó không phải là OOP, chỉ là các chức năng và mô-đun.
Tôi đã cố gắng theo dõi nơi dòng chảy bắt đầu và kết thúc bất cứ khi nào tôi gọi chức năng chính nhưng tôi cảm thấy mình cần phải rút ra điều này vì tôi bị lạc trong các cuộc gọi phụ.

Điều tôi quan tâm là mỗi chức năng gọi nhiều chức năng bên ngoài trong cơ thể của họ để hoàn thành nhiệm vụ của họ và trả lại giá trị cho người gọi.

Làm thế nào tôi có thể vẽ này? Có nghĩa là loại biểu đồ / đồ họa nào sẽ phù hợp để ghi lại loại hành vi / mã này?

Vì vậy, tôi không nghĩ sẽ hữu ích khi vẽ sơ đồ UML, cũng không phải là sơ đồ. Một đồ thị cuộc gọi, có thể?


doxygen - sẽ tạo biểu đồ cuộc gọi / người gọi, tôi không chắc nó có hỗ trợ bao nhiêu cho python. Tôi biết bạn có thể tài liệu mã python cho nó.
gbjbaanb

Tôi đã thử dùng pycallgraph nhưng nó quá phức tạp / quá sâu để sử dụng nó. Điều này là do sự phức tạp của mã của tôi vì nó trộn lẫn python đơn giản với django và cuộc gọi bên ngoài tới url API. Đó là lý do tại sao tôi muốn vẽ nó bằng tay chỉ tính đến phần có liên quan tôi cần. Vấn đề là tôi không biết nên sử dụng loại biểu đồ nào để có hiểu biết đầy đủ về hệ thống
Leonardo

5
Nếu điều này chỉ để giúp bạn hiểu nó, chỉ cần vẽ bất cứ điều gì đến một cách tự nhiên. Bạn luôn có thể dọn dẹp nó sau này nếu nó đi vào tài liệu chính thức.
jonrsharpe

Câu trả lời:


9

Tôi nghĩ những gì bạn đang tìm kiếm ở đây là một Sơ đồ trình tự . Điều này cho phép bạn hình dung thứ tự mà các mô-đun khác nhau gọi nhau thông qua việc sử dụng các mũi tên.

Xây dựng một là đơn giản:

  1. Vẽ lớp bắt đầu của bạn với một đường chấm bên dưới nó.
  2. Vẽ lớp / phương thức tiếp theo trong dấu vết cuộc gọi bằng một đường chấm bên dưới
  3. Kết nối các dòng với một mũi tên, định vị theo chiều dọc bên dưới mũi tên cuối cùng bạn đã vẽ
  4. Lặp lại các bước 2-3 cho tất cả các cuộc gọi trong dấu vết của bạn

Thí dụ

Giả sử chúng ta có mã sau đây, chúng tôi muốn tạo sơ đồ trình tự cho:

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

Điều đầu tiên chúng ta sẽ rút ra là điểm vào ( main) kết nối với phương thức long_division. Lưu ý rằng điều này tạo ra một hộp trong long_division, biểu thị phạm vi của cuộc gọi phương thức. Đối với ví dụ đơn giản này, hộp sẽ là toàn bộ chiều cao của sơ đồ trình tự của chúng tôi do thực tế đây là điều duy nhất chạy.

nhập mô tả hình ảnh ở đây

Bây giờ chúng tôi gọi find_largest_fitđể tìm bội số lớn nhất phù hợp với số làm việc của chúng tôi và trả lại cho chúng tôi. Chúng tôi vẽ một dòng từ long_divisionđến find_largest_fitvới một hộp khác để biểu thị phạm vi cho lệnh gọi hàm. Lưu ý cách hộp kết thúc khi hệ số nhân được trả về; đây là kết thúc của phạm vi chức năng đó!

nhập mô tả hình ảnh ở đây

Lặp lại một vài lần cho một số lớn hơn và biểu đồ của bạn sẽ trông giống như thế này:

nhập mô tả hình ảnh ở đây

Ghi chú

Bạn có thể chọn xem bạn muốn gắn nhãn các cuộc gọi với tên biến được truyền hay giá trị của chúng nếu bạn chỉ muốn ghi lại một trường hợp cụ thể. Bạn cũng có thể hiển thị đệ quy với một hàm gọi chính nó.

Ngoài ra, bạn có thể hiển thị người dùng ở đây và nhắc họ và hiển thị đầu vào của họ vào hệ thống đủ dễ dàng. Đây là một hệ thống khá linh hoạt mà tôi nghĩ bạn sẽ thấy khá hữu ích!


Cảm ơn, tôi biết sơ đồ trình tự, nhưng tôi cảm thấy nó phù hợp hơn với oop. Trong trường hợp của tôi, mọi thứ lộn xộn hơn một chút, có nghĩa là ví dụ tôi có khoảng 20 chức năng / trợ giúp trải rộng trên nhiều mô-đun. Tôi sẽ chỉ định mô-đun mà chức năng thuộc về? Xem xét rằng một số chức năng cũng được đổi tên trong quá trình nhập khẩu ..
Leonardo

1
Tôi sẽ nói rằng không quan trọng bạn có bao nhiêu mô-đun - ví dụ trên không phải là không có gì cả. Chỉ cần đặt tên cho chúng để bạn có thể tìm thấy chúng sau này, ModuleA / function1, ModuleB / Function2, v.v ... Đối với 20 chức năng, nó sẽ lớn hơn, nhưng chắc chắn không thể hiểu được. Một suy nghĩ khác bạn có thể làm là kết thúc dòng cho một chức năng sau lần sử dụng cuối cùng và đặt một dòng chức năng khác bên dưới nó để tiết kiệm không gian ngang trong sơ đồ của bạn.
Ampt

5

Tôi nghĩ rằng một biểu đồ cuộc gọi sẽ là hình dung phù hợp nhất. Nếu bạn quyết định không thực hiện bằng tay, sẽ có một công cụ nhỏ được gọi là pyanphân tích tĩnh trên tệp python và có thể tạo biểu đồ cuộc gọi trực quan bằng tệp chấm graphviz (có thể được hiển thị thành hình ảnh). Đã có một vài dĩa, nhưng cái đầy đủ tính năng nhất dường như là https://github.com/davidfraser/pyan .

Bạn chỉ cần chỉ định tất cả các tệp bạn muốn xử lý khi bạn chạy lệnh:

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

hoặc là

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

Bạn có thể làm cho biểu đồ sạch hơn với '-n' để loại bỏ các dòng hiển thị nơi một hàm được xác định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.