python中的行分析类实例化

python中的行分析类实例化,python,inheritance,instantiation,line-profiler,Python,Inheritance,Instantiation,Line Profiler,我有一些我正在尝试分析的现有代码。通过使用添加@profile decorator,我可以成功地将profile类方法行成一行 是否有一种通用的方法来分析类实例化?我有几个类具有非常复杂的继承结构。当我尝试分析它们的init函数时,我得到如下结果: Line # Hits Time Per Hit % Time Line Contents ==============================================================

我有一些我正在尝试分析的现有代码。通过使用添加@profile decorator,我可以成功地将profile类方法行成一行

是否有一种通用的方法来分析类实例化?我有几个类具有非常复杂的继承结构。当我尝试分析它们的init函数时,我得到如下结果:

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
这有点没用,因为我不知道这个类有两个父函数,每个都有一个或多个父函数正在被调用

有没有更好的办法?例如,是否有一种方法可以自动深入每一行,并以有限的深度分析它调用的行?

有多种方法:

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

尝试在pythonshell中运行以下代码

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__
跟踪模块还具有CLI。上述python代码相当于此shell命令:

python -m trace -T test.py | grep __init__
其中选项-T相当于countcallers=True。 目标脚本test.py应该包含初始化类的最少代码

将line profiler添加到调用的函数中 现在您知道了在类初始化中调用的模块、类和方法的名称。然后您可以将@profile decorator添加到这些函数中。 作为旁注:添加装饰器不需要修改每个模块的源代码。只需将它们导入主模块并运行 profile.add_functionMyDependency.Third.\uuu init\uu 也会有同样的效果

如果希望按时间顺序跟踪调用的所有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方法注册回调函数。当函数被调用或返回时,它将接收堆栈转换事件。每个事件都带有一个堆栈帧对象,您可以从中记录调用的模块、类和函数

这种方法将给你最大的灵活性。例如,可以使用堆栈深度或执行时间长度过滤掉函数调用。 有关用法示例,请参阅my older以了解类似问题

以上示例的文件结构 以上结果基于以下取自的模块/类结构

文件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__()

如果能知道这件事为什么会被否决,那将是非常有帮助的。。如果我可以为这个问题添加一些东西,我很乐意。父类很容易由mro确定,并且在运行时是静态的,除非您在运行时动态创建类。