Python自省:如何检测方法访问了哪些字段
Posted
技术标签:
【中文标题】Python自省:如何检测方法访问了哪些字段【英文标题】:Python introspection: how to detect what fields are accessed from a method 【发布时间】:2012-01-11 10:38:09 【问题描述】:我需要用 Python 执行一些黑魔法。
按照我之前的问题Lazy data-flow (spreadsheet like) properties with dependencies in Python,现在我想通过检查计算函数自动填充派生属性所依赖的字段列表。
我想我可以使用func_code.co_names
属性,但我不太确定那里是否有一些警告,documentation 并没有多大帮助。
有什么想法吗?
【问题讨论】:
【参考方案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
是来自封闭非全局范围的变量。
【讨论】:
以上是关于Python自省:如何检测方法访问了哪些字段的主要内容,如果未能解决你的问题,请参考以下文章