Намалюйте графік викликів


12

Я підтримую стару базу коду, написану в python. Зокрема, існує складний фрагмент коду, який з модуля викликає інші функції з інших модулів, які викликають інші функції тощо. Це не OOP, а лише функції та модулі.
Я намагався відстежувати, де починається і закінчується потік у будь-який час, коли я називаю основну функцію, але відчуваю, що мені потрібно це зробити, тому що я втрачаюсь у підзакликах.

Мене хвилює те, що кожна функція викликає декілька зовнішніх функцій у своєму тілі, щоб виконати своє завдання і повернути значення абоненту.

Як я можу це намалювати? Значить, який тип діаграми / графіки було б доречним для документування такого типу поведінки / коду?

Отже, я не думаю, що було б корисно накреслити діаграму UML, а також блок-схему. Графік виклику, можливо?


doxygen - генерує графіки викликів / викликів, я не впевнений, яку підтримку має python. Я знаю, що ви можете документувати код python для цього.
gbjbaanb

Я спробував pycallgraph, але він занадто складний / занадто глибокий, щоб використовувати його. Це пов’язано зі складністю мого коду, оскільки він змішує звичайний пітон з django та зовнішнім викликом URL-адреси API. Ось чому я хотів намалювати його вручну лише з урахуванням потрібної мені частини. Проблема полягає в тому, що я не знаю, який графік використовувати для повного розуміння системи
Леонардо

5
Якщо це просто, щоб допомогти вам зрозуміти це, просто намалюйте все, що відбувається природним шляхом. Ви завжди можете прибирати його згодом пізніше, якщо мова йде про офіційну документацію.
jonrsharpe

Відповіді:


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_divisionдо find_largest_fitдо іншого поля, щоб позначити область для виклику функції. Зверніть увагу, як закінчується вікно при поверненні множника; це кінець цієї області функцій!

введіть тут опис зображення

Повторіть кілька разів для більшої кількості, і ваш графік повинен виглядати приблизно так:

введіть тут опис зображення

Примітки

Ви можете вибрати, чи хочете ви позначити виклики передаваними іменами змінних або їх значеннями, якщо потрібно документувати лише один конкретний випадок. Ви також можете показати рекурсію за допомогою функції, що викликає себе.

Крім того, ви можете показати користувачам тут і запропонувати їм та показати їх вхід у систему досить легко. Це досить гнучка система, на вашу думку, ви знайдете досить корисною!


Дякую, я знаю діаграму послідовностей, але мені здається, вона більше підходить для oop. У моєму випадку речі дещо брудніше, це означає, що, наприклад, у мене є близько 20 функцій / помічників, рознесених по декількох модулях. Хо б я вказав модуль, якому належить функція? Враховуючи, що деякі функції також перейменовані під час імпорту ..
Леонардо

1
Я б сказав, що не має значення, скільки у вас є модулів - тож вище приклад не є взагалі. Просто назвіть їх, щоб ви могли їх знайти пізніше, ModuleA / function1, ModuleB / Function2 і т. Д. Для 20 функцій його буде більше, але, безумовно, неможливо зрозуміти. Ще одна думка, яку ви можете зробити, - це закінчити рядок функції після її останнього використання та поставити під неї іншу рядок функцій, щоб зберегти горизонтальний простір у вашій діаграмі.
Ampt

7

Я думаю, що графік викликів був би найбільш підходящою візуалізацією. Якщо ви вирішили не робити це вручну, є приємний маленький інструмент, який називається 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', який видаляє рядки, що показують, де визначена функція.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.