【问题标题】:Python introspection: how to detect what fields are accessed from a methodPython自省:如何检测方法访问了哪些字段
【发布时间】:2012-01-11 10:38:09
【问题描述】:

我需要用 Python 执行一些黑魔法。

按照我之前的问题Lazy data-flow (spreadsheet like) properties with dependencies in Python,现在我想通过检查计算函数自动填充派生属性所依赖的字段列表。

我想我可以使用func_code.co_names 属性,但我不太确定那里是否有一些警告,documentation 并没有多大帮助。

有什么想法吗?

【问题讨论】:

    标签: 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 是来自封闭非全局范围的变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-12
      • 2022-01-16
      • 1970-01-01
      • 2019-11-01
      • 2015-01-11
      • 1970-01-01
      相关资源
      最近更新 更多