![](/img/trans.png)
[英]How can I know in Python how many times a line of code is executed per minute?
[英]Python: counting how many times a given line is executed
出于教学目的,我想计算一个给定行在给定函数中执行多少次而不修改或装饰它 。 例如,对于功能:
def binary_search(seq, x):
(a, b) = (0, len(seq) - 1)
while a <= b:
m = (a + b) / 2
if x < seq[m]:
b = m - 1
elif x > seq[m]:
a = m + 1
else:
return m
我会写这样的东西:
print count_exec(binary_search, range(100), 44, line_number = 4)
......甚至是这样的:
print count_exec(binary_search(range(100), 44), line = "m = (a + b) / 2")
...两者都应该打印执行第4行的次数(即7)。 最终目标是为任何功能的复杂性提供经验方法:
我目前的解决方案是添加一个函数属性:
def binary_search(seq, x):
binary_search.count = 0 # <------------------ added
(a, b) = (0, len(seq) - 1)
while a <= b:
binary_search.count += 1 # <------------- added
m = (a + b) / 2
if x < seq[m]:
b = m - 1
elif x > seq[m]:
a = m + 1
else:
return m
binary_search(range(100), 44)
print binary_search.count
我想我可以创建一个装饰函数count_this_line
:
def binary_search(seq, x):
(a, b) = (0, len(seq) - 1)
while a <= b:
count_this_line() # <-------------------- added
m = (a + b) / 2
...
也许可以装饰函数binary_search
本身,但对我来说,这就像修改它一样。
您可以使用line_profiler
模块执行此操作( 请参阅文档 )。 请注意,我必须从分叉回购中获得3.x兼容版本 - 不确定它是否已合并。
例如。 我把你的二进制搜索功能放在一个文件中,然后添加:
prof = profile(binary_search)
prof(range(100), 44)
这与文档中提到的@profile
装饰器相同,但您不必修改原始代码。 我跑了
kernprof.py -l binsearch.py
python -m line_profiler binsearch.py.lprof
突然出现了这个:
Function: binary_search at line 1
Total time: 4.1e-05 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
1 def binary_search(seq, x):
2 1 6 6.0 14.6 (a, b) = (0, len(seq) - 1)
3 7 8 1.1 19.5 while a <= b:
4 7 7 1.0 17.1 m = (a + b) // 2
5 7 8 1.1 19.5 if x < seq[m]:
6 2 2 1.0 4.9 b = m - 1
7 5 5 1.0 12.2 elif x > seq[m]:
8 4 4 1.0 9.8 a = m + 1
9 else:
10 1 1 1.0 2.4 return m
“Hits”是您正在寻找的数字。 作为奖励,您也可以获得时间信息,但是对于许多执行来说这会更准确。
根据Jason的建议,我编写了一个纯Python解决方案:
import line_profiler
import __builtin__
import cStringIO
import re
def profile(path, function_call, line_number):
prof = line_profiler.LineProfiler()
__builtin__.__dict__['profile'] = prof
script = open(path).read()
ns = locals()
function_name = function_call[:function_call.index("(")]
rex = re.compile("((?ms)^def %s.+)" % function_name)
script = rex.sub(r"@profile\n\1\n%s" % function_call, script)
exec(script, ns, ns)
stream = cStringIO.StringIO()
prof.print_stats(stream)
s = stream.getvalue()
stream.close()
return int(re.search(r"(?m)^\s*%s\s*(\S*)" % (line_number+1), s).group(1))
if __name__ == "__main__":
print profile("binary_search.py", "binary_search(range(100), 44)", 3)
它读取包含要分析的函数的脚本的源,装饰这个,将所需的调用追加到结尾,执行它,将统计信息转储到字符串中,提取给定行号的命中数,并将其返回为一个int
。 它按要求工作,但具有重要的性能损失。
也许更好的解决方案是删除分析器,但保持动态装饰和执行源代码的想法。 如果我植入它,我会编辑我的答案。
无论如何,谢谢Jason为我提供了一条出路!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.