跟踪Python中调用内置函数的位置

跟踪Python中调用内置函数的位置,python,debugging,Python,Debugging,当我使用cProfile一个程序时,我发现我花了很多时间打昂贵的zip电话。我编写的代码没有进行这些zip调用,所以它一定是我从导入的许多库中引入的代码 有没有一个工具可以让我标记一个函数调用,并告诉我哪些函数在Python中调用了该函数?不久前,我遇到了一个类似于您的问题,我设法解决了它。这不是一个工具,但可能对你有用。只需将以下代码放在主模块的顶部 注意:该代码是为您所需的zip功能定制的,对我来说它可以工作(当然还有另一个功能,我现在不记得它的名字了)。我额外导入的是我应用程序中的第三方模

当我使用
cProfile
一个程序时,我发现我花了很多时间打昂贵的
zip
电话。我编写的代码没有进行这些zip调用,所以它一定是我从导入的许多库中引入的代码


有没有一个工具可以让我标记一个函数调用,并告诉我哪些函数在Python中调用了该函数?

不久前,我遇到了一个类似于您的问题,我设法解决了它。这不是一个工具,但可能对你有用。只需将以下代码放在主模块的顶部

注意:该代码是为您所需的
zip
功能定制的,对我来说它可以工作(当然还有另一个功能,我现在不记得它的名字了)。我额外导入的是我应用程序中的第三方模块,我不知道它是否适用于标准库中的模块

import inspect

def trackZip(*args):
    print inspect.getouterframes(inspect.currentframe())[1]
    return __builtins__.zip(*args)

zip = trackZip

#do more imports...

def test():
    zip([1,2],[3,4])

test()
zip([1,2],[3,4])
输出:

(<frame object at 0x1948260>, '/home/user/untitled4.py', 17, 'test', ['    zip([1,2],[3,4])\n'], 0)
(<frame object at 0x11fd3d0>, '/home/user/untitled4.py', 20, '<module>', ['zip([1,2],[3,4])\n'], 0)
(,'/home/user/untitled4.py',17,'test',['zip([1,2],[3,4])\n'],0)
(,'/home/user/untitled4.py',20',,['zip([1,2],[3,4])\n'],0)

A实现所需功能的快捷方法非常简单:用自定义功能替换内置的
zip

[8]中的
:导入检查
在[9]中:定义my_zip(*iterables):
…:frame=inspect.currentframe().f_back
…:my_zip.callees.append(frame.f_code.co_name)
…:返回我的拉链。旧拉链(*iterables)
在[10]:my_zip.callees=[]
在[11]中:my_-zip.old_-zip=zip
在[12]中:导入内置项
在[13]中:builtins.zip=my_-zip
In[14]:zip(范围(5),范围(4))
出[14]:
在[15]:zip.callees中,在模块级调用。。。
Out[15]:['']
(在python2中,将
内置
模块替换为
内置

更智能的实现将使用
collections.Counter
,并避免保留调用
zip
的所有函数名的列表

但是,您可能需要知道的不仅仅是
zip
的呼叫者的姓名。也许还有另一个函数
f
调用
g
调用
h
调用
zip
,但是要知道
f
是问题的真正原因,你必须以某种方式将
h
f
联系起来

扩展
my_-zip
以跟踪更多信息应该不难


然而,我相信
cProfile
的输出应该提供足够的时间信息,以便或多或少地理解
zip
的调用位置。您尤其应该仔细研究其输出的
cumtime

您还应该考虑调用函数的次数。通常一个函数在被调用时总是执行相同数量的
zip
s,因此对
zip
和“罪魁祸首”函数的调用次数在某种程度上应该是成比例的


当然,隐藏这些关系的噪音可能很多,但你应该试着弄清楚

您可以从探查器输出中获取该信息。从输出创建一个对象并调用
stats.print\u调用者('zip')


这应该向您显示调用它的函数,以及每个调用方调用它的次数,以及调用中花费的总时间和累计时间。

我相信
cProfile
的输出已经为您提供了在函数累计成本中“隐藏”的信息。提供
cProfile
的输出会很有帮助。
In [8]: import inspect
In [9]: def my_zip(*iterables):
   ...:     frame = inspect.currentframe().f_back
   ...:     my_zip.callees.append(frame.f_code.co_name)
   ...:     return my_zip.old_zip(*iterables)

In [10]: my_zip.callees = []

In [11]: my_zip.old_zip = zip

In [12]: import builtins

In [13]: builtins.zip = my_zip

In [14]: zip(range(5), range(4))
Out[14]: <builtins.zip at 0x7f06a2324290>

In [15]: zip.callees  # called at module level...
Out[15]: ['<module>']