【问题标题】:Python introspection: how to detect what fields are accessed from a methodPython自省:如何检测方法访问了哪些字段
【发布时间】:2012-01-11 10:38:09
【问题描述】:
【问题讨论】:
标签:
python
methods
properties
introspection
【解决方案1】:
不幸的是,func_code.co_names 不太可能有太大帮助。这包含代码段内访问的所有名称,包括全局变量,按出现顺序排列。
class Test(object):
def calc_a(self):
return self.b + self.c
def calc_x(self):
return self.y.a + self.y.b
>>> Test.calc_a.func_code.co_names
('b', 'c')
>>> Test.calc_x.func_code.co_names
('y', 'a', 'b')
无法从这个数组中判断“a”和“b”是从“self”还是从“self.y”加载的。一般来说,不执行一段代码就知道其访问模式的唯一方法是反汇编它。
>>> import dis
>>> dis.dis(Test.calc_x)
23 0 LOAD_FAST 0 (self)
3 LOAD_ATTR 0 (y)
6 LOAD_ATTR 1 (a)
9 LOAD_FAST 0 (self)
12 LOAD_ATTR 0 (y)
15 LOAD_ATTR 2 (b)
18 BINARY_ADD
19 RETURN_VALUE
我们看到该函数加载“self”变量(对于绑定函数,它始终为co_varnames[0]),然后从该对象加载属性“y”(co_names[0]),然后从该对象加载属性“a”(co_names[1])。从 self.y.b 中推送第二个堆栈对象,然后将两者相加。
查看标准库中dis.py的源码,看看C Python二进制代码是如何反汇编的。第 0 个变量的负载对于绑定函数很重要。另一个方便的点是函数的参数是 co_varnames[:co_argcount](其余或 varnames 是本地变量),co_freevars 是来自封闭非全局范围的变量。