我有一个Python应用程序,我希望在运行时监视标准随机模块中函数的调用次数;有什么好方法可以做到这一点,还是我必须“手动”做到这一点?
答案 0 :(得分:7)
在我看来,Python分析器应该能够“很好地”完成它。请看a post about Python profiling on SO。
在运行时,似乎decorators是可行的方法。当然,默认随机模块没有装饰器,因此您可能需要定义带有装饰器的monitoredrandom模块,这些装饰器代理随机模块并对调用进行计数。如果保持函数名称和签名与随机相同,则只需修改代码中的导入。
答案 1 :(得分:4)
这是一个肮脏的解决方案:
import functools
def monitor(f):
@functools.wraps(f)
def decorated(*args, **kwargs):
print("{}: {}, {}".format(f.__name__, args, kwargs))
# Do whatever you want: increment some counter, etc.
return f(*args, **kwargs)
return decorated
import random
for name in dir(random):
f = getattr(random, name)
if callable(f) and not name.startswith('_'):
setattr(random, name, monitor(f))
此代码应在程序的最开始执行(可以在单独的模块中),在任何其他代码之前执行,包括导入。
答案 2 :(得分:3)
创建一个包装函数,增加计数,然后进行调用并返回结果。
如果您考虑“手动”,那么是。
答案 3 :(得分:2)
我能想到的最好的是代理 - 我不相信用自定义的dict-esque对象替换sys.modules是可能的。注意我不喜欢这个,而且你自己就是这样......
class random(object):
def __init__(self):
from collections import defaultdict
import random as r_
self.R = r_
self.__lookups = defaultdict(int)
def __getattr__(self, name):
self.__lookups[name] += 1
return getattr(self.R, name)
@property
def freq(self):
return self.__lookups
可怕的kludge但实际上是标准模块的代理。如何将它放入命名空间我真的不确定 - 也许把它放在一个模块中,然后(现在建立名称)from random_testing import random
而不是正常的import random
。
我注意到通过这种方法运行两个randint
给了我六个计数 - 所以不完全确定内部是如何在那里工作的....
答案 4 :(得分:1)
cProfile
返回每个函数的调用次数。
这样的事情应该有效:
import my_module
import cProfile
cProfile.run('my_module.my_func()')
其中my_module.my_func是程序的入口点。这输出如下:
7 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 bar.py:4(bar)
1 0.000 0.000 0.000 0.000 foo.py:4(foo)
1 0.000 0.000 0.000 0.000 my_module.py:4(my_func)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 0.000 0.000 0.000 0.000 {method 'random' of '_random.Random' objects}
最后一行显示总共有2次调用随机方法(在我的玩具示例中有两个不同的模块,foo.py和bar.py)。
编辑:当然,这只有在您希望计数离线时才有用,正如评论中所指出的那样。