首页 > 解决方案 > python中的行分析类实例化

问题描述

我有一些我正在尝试分析的现有代码。我可以通过使用kernprof@profile添加装饰器来成功地配置配置文件类方法。

有没有一种通用的方法来分析类实例化?我有一些具有相当复杂的继承结构的类。当我尝试分析他们的初始化函数时,我得到如下信息:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   179                                               def __init__(self, data):
   180         1    8910739.0 8910739.0    100.0          super().__init__(data)
   181         1         10.0      10.0      0.0          self.mortgage_rate = 5.2  # rate in percentage

这有点没用,因为我不知道__init__正在调用什么实际的父函数(这个类有 2 个父函数,每个父函数都有一个或多个父函数)。

有没有办法更好地做到这一点?例如,有没有办法自动深入每一行,并分析被它调用的行(深度有限)?

标签: pythoninheritanceinstantiationline-profiler

解决方案


有很多方法:

trace模块_

标准 python 库中的跟踪模块提供了一个方便的函数来逐行跟踪程序的执行。因此,很容易找出您的__init__方法调用了哪个函数。

尝试在 python shell 中运行以下代码

from MyMod import MyClass
# Do necessary preparation for your module HERE

# --- Setup and start tracing ---
import sys, trace
tracer = trace.Trace( trace=0, count=0, timing=True,  countcallers=True)
tracer.run('MyClass()') # init your class and track the function calls
tracer.results().write_results(show_missing=False) # print result to the screen

跟踪器将显示通过运行程序暴露的调用关系。

MyDependency.Fourth.__init__ -> MyDependency.Second.__init__
MyDependency.Second.__init__ -> MyDependency.Third.__init__
MyDependency.Third.__init__ -> MyDependency.First.__init__
MyClass.Child.__init__ -> MyDependency.Fourth.__init__

trace模块还有一个 CLI。上面的 python 代码等价于这个 shell 命令:

python -m trace -T test.py | grep __init__

其中 option-T等价于countcallers=True. 目标脚本test.py应该包含最少的代码来初始化你的类。

将 line-profiler 添加到调用的函数

现在您知道了在类初始化中调用的模块、类和方法的名称。然后你可以@profile为这些函数添加装饰器。附带说明:不需要修改每个模块的源代码来添加装饰器。只需将它们导入您的主模块并运行 profile.add_function(MyDependency.Third.__init__) 将具有相同的效果。

如果您想按时间顺序跟踪调用的所有 Python 代码行,请使用以下选项

tracer = trace.Trace( ignoredirs=[sys.prefix, sys.exec_prefix ], trace=1, count=0, timing=True )

它会打印出来

 --- modulename: MyMod, funcname: __init__
0.00 MyMod.py(6):         super().__init__()
 --- modulename: MyDependency, funcname: __init__
0.00 MyDependency.py(17):         super().__init__()
...

其中第一列是步行时钟时间。

sys.setprofile方法_

sys.setprofile您可以通过该方法注册一个回调函数。它将接收堆栈转换事件(当函数被调用或返回时)。每个事件都带有一个堆栈框架对象,您可以从中记录模块、类和调用的函数。

这种方法会给你最大的灵活性。例如,您可以过滤掉具有堆栈深度或执行时间长度的函数调用。有关用法示例,请参阅我较早的帖子以获取类似的问题。

上述示例的文件结构

以上结果基于从另一篇文章中获取的以下模块/类结构。

文件“MyDependency.py”

class First:
    ...
class Second(First):
    ...
class Third(First):
    ...
class Fourth(Second, Third):
    ...

文件“MyModel.py”

from MyDependency import Fourth
class MyClass(Fourth):
    def __init__(self):
        super().__init__()

推荐阅读