Неграфический вывод из pycallgraph

Я начал писать небольшую утилиту Python для кеширования функций. Доступные инструменты кеширования (lru_cache, Мензурка) не обнаруживает изменения подфункций.

Для этого мне нужен Call Call. Существует великолепный инструмент в pycallgraph Gerald Kaszuba. Тем не менее, до сих пор я получил его только для вывода строк с именами функций. Что мне нужно, так это функциональные объекты или хеши кода функций.

Что я имею в виду с этими двумя терминами: пусть def foo(x): return x, затем foo является функцией-объектом, и hash(foo.__code__.co_code) это хэш-код функции

Что я имею

Вы можете увидеть, что у меня здесь. Но ниже приведен минимальный пример. Проблема, с которой я столкнулся в этом примере, заключается в том, что я не могу снова перейти от имени функции (строки) к определению функции. Я пытаюсь с eval(func),

Итак, я думаю, есть два способа решения этой проблемы:

  1. правильный pycallgraph.outputили каким-то другим способом получить то, что я хочу, прямо из Pycallgraph.
  2. Динамическая загрузка функции из function.__name__ строка.

import unittest
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

class Callgraph:
    def __init__(self, output_file='callgraph.png'):
        self.graphviz = GraphvizOutput()
        self.graphviz.output_file = output_file

    def execute(self, function, *args, **kwargs):
        with PyCallGraph(output=self.graphviz):
            ret = function(*args, **kwargs)

        self.graph = dict()
        for node in self.graphviz.processor.nodes():
            if node.name != '__main__':
                f = eval(node.name)
                self.graph[node.name] = hash(f.__code__.co_code)
        return ret

    def unchanged(self):
        '''Checks each function in the callgraph whether it has changed.
        Returns True if all the function have their original code-hash. False otherwise.
        '''
        for func, codehash in self.graph.iteritems():
            f = eval(func)
            if hash(f.__code__.co_code) != codehash:
                return False
        return True

def func_inner(x):
    return x
def func_outer(x):
    return 2*func_inner(x)

class CallgraphTest(unittest.TestCase):
    def testChanges(self):
        cg = Callgraph()
        y = cg.execute(func_outer, 3)
        self.assertEqual(6, y)
        self.assertTrue(cg.unchanged())
        # Change one of the functions
        def func_inner(x):
            return 3+x
        self.assertFalse(cg.unchanged())
        # Change back!
        def func_inner(x):
            return x
        self.assertTrue(cg.unchanged())


if __name__ == '__main__':
    unittest.main()

1 ответ

Решение

Я решил это путем исправления tracer.py с соответствующими хешами.

         # Work out the current function or method
         func_name = code.co_name
+        func_hash = hash(code.co_code)

Я рассчитываю значение только там, где имя функции сохраняется. Позже вам, очевидно, также потребуется сохранить это значение. Я делаю это со словарем, где func_name является ключом, а хэш является значением. В функции, где создаются узлы, я назначаю это новому полю в stat_group,

Другие вопросы по тегам