我已经开始编写一个小的Python实用程序来缓存功能。可用的缓存工具(lru_cache
,烧杯)无法检测到子功能的更改。
为此,我需要一个调用图。存在着一个极好的工具pycallgraph由杰拉尔德Kaszuba。但是,到目前为止,我只能输出功能名称字符串。我需要的是函数对象或函数代码哈希。
我用这两个术语的意思是:让def foo(x): return x
,然后foo
是功能对象,然后hash(foo.__code__.co_code)
是功能代码哈希。
你可以在这里看到我的东西。但是下面是一个最小的示例。在此示例中,我遇到的问题是我无法再从函数名称(字符串)转到函数定义。我正在尝试eval(func)
。
因此,我想有两种解决方法:
pycallgraph.output
,或者通过其他方式直接从Pycallgraph获得我想要的东西。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()
我已经通过修补tracer.py
适当的哈希值解决了这一问题。
# Work out the current function or method
func_name = code.co_name
+ func_hash = hash(code.co_code)
我正在计算的值正好保存在函数名中。稍后,您显然还需要保存该值。我使用字典func_name
作为键,哈希是值。在创建节点的函数中,我将其分配给中的新字段stat_group
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句