在运行时跟踪方法解析顺序

时间:2017-01-27 09:10:25

标签: django trace

我正在研究一些代码(不是我的代码),我试图将其设置为。

继承树中有16个类。

根据inspect.getmro(self.__class__)

区分该类
  • foo_barcheck.views.barcheck.AdminListActionView
  • foo_barcheck.views.barcheck.ListActionMixin
  • djangotools.utils.urlresolverutils.UrlMixin
  • foo.views.ListActionView
  • foo.views.ContextMixin
  • foo.views.fooMixin
  • djangotools.views.ListActionView
  • djangotools.views.ListViewMixin
  • django.views.generic.list.MultipleObjectMixin
  • django.views.generic.edit.FormMixin
  • djangotools.views.DTMixin
  • django.views.generic.base.TemplateView
  • django.views.generic.base.TemplateResponseMixin
  • django.views.generic.base.ContextMixin
  • django.views.generic.base.View
  • 物体

我想跟踪一下如果我拨打self.do_magic()会发生什么。

我希望看到这16个类的所有do_magic()次调用。

理想的解决方案如下:

result_of_do_magic, list_of_do_magic_methods = trace_method_calls(self.do_magic)

我不知道如何实施trace_method_calls()。它应该执行代码并在运行时跟踪方法调用。

是否有一位追踪专家知道如何做到这一点?

AFAIK这需要在运行时完成,因为我不知道所有方法是否都通过do_magic()调用父母的super()

更新

我不想修改代码以便能够跟踪它。我想这应该是可能的,因为模拟库可以做类似的魔术。

2 个答案:

答案 0 :(得分:4)

如果我理解正确,我可以在这里看到2个解决方案。

1)[Brute-ish且相对简单]查找所有出现的" do_magic"在你的代码中,用装饰器包装它,如:

def trace_this(fn):
    def wrapped(*args, **kwargs):
        print("do_magic is called!")
        result = fn(*args, **kwargs)
        print("Result is:{0}".format(result))
        return result
return wrapped
...
@trace_this
def do_magic():
    ...

2)运行django as:

python -m trace -t manage.py runserver 127.0.0.1:8000 --noreload > trace.txt

并且所有调用的代码都在trace.txt中,然后您可以使用自己喜欢的工具进行解析/分析。

答案 1 :(得分:0)

根据我的理解,您想要的是特定函数的外部框架调用,以查看调用哪些类来导致相关方法。

如果您想继续下面的内容,请在评论中告诉我:

下面是一个POC来演示它是如何工作的。你可以用它来构建一个装饰器。

from __future__ import print_function
import inspect


class A:
    def a(self):
        stacks = inspect.getouterframes(inspect.currentframe())
        for stack in stacks:
            frame = stack[0]
            klass = frame.f_locals.get("self")
            mthd = frame.f_code.co_name
            if klass: # to avoid printing modules
                print('Called by class: {0}, method: {1}'.format(klass.__class__.__name__, mthd))

class B:
    def b(self):
        bb = A()
        bb.a()

class C:
    def c(self):
        cc = B()
        cc.b()

z = C()
z.c()

输出:

enter image description here

说明:

  1. Class C拨打Class B,然后拨打Class A
  2. 当执行到达A.a()时,所有继承A的类都在外框中。
  3. 您可以只提取A.a()的功能来创建装饰器,以便打印通向函数调用的所有外框。