来自pycallgraph的非图形输出

时间:2014-12-05 20:23:03

标签: python pycallgraph

我开始编写一个小的Python实用程序来缓存函数。可用的缓存工具(lru_cacheBeaker)不会检测子功能的更改。

为此,我需要一个调用图pycallgraph Gerald Kaszuba中有一个很好的工具。但是,到目前为止,我只能输出函数名字符串。我需要的是 function-objects function-code-hashes。

我对这两个术语的含义是:设def foo(x): return x,然后foo是函数对象,hash(foo.__code__.co_code)函数 - 代码 - 哈希

我拥有什么

你可以看到我拥有的here。但下面是一个最小的例子。我在这个例子中遇到的问题是,我不能再从函数名(字符串)转到函数定义。我正在尝试使用eval(func)

所以,我猜有两种方法可以解决这个问题:

  1. 正确的pycallgraph.output,或其他方式直接从Pycallgraph获得我想要的东西。
  2. function.__name__字符串动态加载函数。

  3. 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 个答案:

答案 0 :(得分:0)

我通过使用适当的哈希值修补tracer.py来解决这个问题。

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

我正在计算保存函数名称的值。后来,你显然也需要保存这个价值。我正在使用字典,其中func_name是键,哈希是值。在创建节点的函数中,我将其分配给stat_group中的新字段。