运行时跟踪方法解析顺序

Trace method resolution order at runtime

我正在写一些代码(不是我的),我试着去理解它。

继承树中有 16 个 class。

此处区域class根据inspect.getmro(self.__class__)

我想跟踪调用 self.do_magic() 时会发生什么。

我想查看这 16 个 class 的所有 do_magic() 个调用。

理想的解决方案如下所示:

result_of_do_magic, list_of_do_magic_methods = trace_method_calls(self.do_magic)

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

有没有知道如何做到这一点的跟踪大师?

据我所知,这需要在运行时完成,因为我不知道是否所有方法都通过 super().

调用 parents 的 do_magic()

更新

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

如果我没理解错的话,这里可以看到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 为:

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

所有调用的代码都在 trace.txt 中,然后您可以 parse/analyze 使用您喜欢的工具。

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

如果这是你想要的,请继续下面的内容,否则请在评论中告诉我:

下面是一个 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()

输出:

解释:

  1. Class C 调用 Class B,后者又调用 Class A
  2. 当执行到 A.a() 时,继承 A 的所有 类 都在外部框架中。
  3. 您可以仅提取 A.a() 的功能来创建装饰器,以便它打印函数调用之前的所有外部框架。