运行时跟踪方法解析顺序
Trace method resolution order at runtime
我正在写一些代码(不是我的),我试着去理解它。
继承树中有 16 个 class。
此处区域class根据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
- object
我想跟踪调用 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()
输出:
解释:
Class C
调用 Class B
,后者又调用 Class A
- 当执行到
A.a()
时,继承 A
的所有 类 都在外部框架中。
- 您可以仅提取
A.a()
的功能来创建装饰器,以便它打印函数调用之前的所有外部框架。
我正在写一些代码(不是我的),我试着去理解它。
继承树中有 16 个 class。
此处区域class根据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
- object
我想跟踪调用 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()
.
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()
输出:
解释:
Class C
调用Class B
,后者又调用Class A
- 当执行到
A.a()
时,继承A
的所有 类 都在外部框架中。 - 您可以仅提取
A.a()
的功能来创建装饰器,以便它打印函数调用之前的所有外部框架。