查找 python 内置函数的调用者

Posted

技术标签:

【中文标题】查找 python 内置函数的调用者【英文标题】:find caller of python builtins 【发布时间】:2019-09-12 16:11:05 【问题描述】:

这类似于Profiling in Python: Who called the function? 但有一点不同。我有一个 python 函数,我正在使用 cProfile 进行分析。在我的第一次运行中,统计数据显示它大部分时间都花在了get_loc()datetimes.py

好的,我在我的系统上找到了datetimes.py文件,并在get_loc()的顶部临时添加了import pdbpdb.set_trace(),然后随机使用调试器命令where几次,或多或少在wheres 之间的continue 的随机数。这向我表明,根据我的随机样本,几乎所有对get_loc() 的数千次调用最终都来自我自己代码中的同一位置。我修改了该代码以显着减少调用次数。太好了!

接下来,我现在看到大量时间花费在超过 66,000builtins.isinstance() 的调用中;问题是我找不到实现堆栈跟踪以找出调用isinstance() 的源代码。 (我猜测,基于我对 Python 的有限了解,isinstance 实际上是直接或通过共享对象链接到 Python 解释器的 C 代码)。无论如何,我找不到调用的是isinstance。我尝试了在Profiling in Python: Who called the function? 的答案中也找到的 Gprof2dot 方法 但这仅表明isinstance() 正在被is_dtype() 调用并且调用图停在那里(@987654339 @)。

有什么想法吗?

【问题讨论】:

【参考方案1】:

我已经进行了一些挖掘,并将尝试至少部分回答我的问题(希望其他人会看到并就如何使这更容易提供更多想法)。

这就是我如何描述我的功能

pr = cProfile.Profile()                # create a cProfiler object 
pr.enable()                            # turn profiling on
pr.runcall( myfunc, arg1, arg2, ... )  # profile my function
pr.disable()                           # turn profiling off

那么,这里是寻找来电者的关键:

import pstats
p = pstats.Stats(pr)           # create pstats obj based on profiler above.
p.print_callers('isinstance')  # find all the callers of isinstance.

print_callers 函数打印出 130 个 isinstance 的调用者,以及每个调用者调用 isinstance 的次数。这需要消化很多,但出于分析目的,关注调用最多的少数几个并找到他们的调用者是有意义的。这是列表的一部分(print_callers 以或多或少的随机顺序呈现,但我在这里根据调用次数对它们进行了排序)...

Function built-in method builtins.isinstance was called by...
                                           ncalls  tottime  cumtime
                                             2808    0.002    0.002  /anaconda3/lib/python3.7/site-packages/pandas/core/indexes/datetimes.py:974(get_loc)
                                             2158    0.006    0.018 /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/base.py:75(is_dtype)
                                             2030    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1845(_is_dtype_type)
                                             1930    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1981(pandas_dtype)
                                             1440    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/dtypes.py:68(find)
                                             1058    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/indexes/datetimes.py:924(get_value)
                                              841    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1809(_get_dtype)
                                              726    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1702(is_extension_arr
...
                                                6    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py:153(_get_setitem_indexer)
                                                5    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/ops.py:1660(wrapper)
                                                5    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/ops.py:1447(_align_method_SERIES)
                                                5    0.000    0.000 /anaconda3/lib/python3.7/site-packages/pandas/core/computation/expressions.py:163(_has_bool_dtype)
                                                4    0.000    0.000 /anaconda3/lib/python3.7/site-packages/pandas/core/internals/blocks.py:3100(_extend_blocks)
                                                4    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py:2501(check_setitem_lengths)
                                                3    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/indexes/base.py:566(_shallow_copy)
                                                3    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:702(is_datetimelike)
                                                3    0.000    0.000  /anaconda3/lib/python3.7/posixpath.py:41(_get_sep)
                                                2    0.000    0.000  /anaconda3/lib/python3.7/distutils/version.py:331(_cmp)

在这一点上,我想我可以乏味地检查最大的调用者(找到他们最大的调用者,等等)或编写一个脚本来完成它。将继续挖掘并在以后发布更多进展。

【讨论】:

以上是关于查找 python 内置函数的调用者的主要内容,如果未能解决你的问题,请参考以下文章

查找内置 Python 函数的源代码?

0518Python基础-内置函数-二分查找

使用python中的内置函数查找3d距离

python Python - inspect - 获取完整的调用者信息:包,模块,(类),函数,行。

python协程函数递归匿名函数与内置函数使用模块与包

python基础12_匿名_内置函数