如何确定方法中引用了哪些自属性?

时间:2014-01-16 04:06:35

标签: python

假设:

class A(object):
  def m(self):
    print self.x + self.y + self.z()

有没有办法查询:

self_attributes_referenced(A.m) #=> ['x', 'y']

没有做反编译或解析?

是否有相应的方法来调用自我方法?

self_methods_referenced(A.m) #=> ['z']

2 个答案:

答案 0 :(得分:1)

这样的事情应该有效:

import inspect


class Referee(object):
    def __getattribute__(self, name):
        attr = object.__getattribute__(self, name)
        if inspect.ismethod(attr):
            try:
                meths_referenced = object.__getattribute__(
                    self, 'meths_referenced')
            except AttributeError:
                meths_referenced = set()
                object.__setattr__(self, 'meths_referenced', meths_referenced)

            meths_referenced.add(name)
        else:
            try:
                attrs_referenced = object.__getattribute__(
                    self, 'attrs_referenced')
            except AttributeError:
                attrs_referenced = set()
                object.__setattr__(self, 'attrs_referenced', attrs_referenced)

            attrs_referenced.add(name)

        return attr


def attributes_referenced(obj):
    try:
        return object.__getattribute__(obj, 'attrs_referenced')
    except AttributeError:
        return set()


def methods_referenced(obj):
    try:
        return object.__getattribute__(obj, 'meths_referenced')
    except AttributeError:
        return set()


class A(Referee):
    def __init__(self):
        self.x = 1
        self.y = 2

    def z(self):
        return 3

    def m(self):
        print self.x + self.y + self.z()


a = A()
a.m()
print attributes_referenced(a)
print methods_referenced(a)

打印:

6
set(['y', 'x'])
set(['z', 'm'])

只要您想提供此功能,就从Referee继承。 为什么您需要此功能是我无法理解的。 =)

答案 1 :(得分:1)

在您将解析作为解决方案排除的问题中,您是否意识到使用ast module解析和修改Python源代码有多么轻松?

首先定义NodeTransformer

import ast

class RecordReferencesTransformer(ast.NodeTransformer):
    def visit_FunctionDef(self, node):
        def is_attr_on_self(n):
            return type(n) is ast.Attribute and type(n.value) is ast.Name and n.value.id == 'self'

        targets = [ast.Attribute(value=ast.Name(id=node.name, ctx=ast.Load()), attr='self_attributes_referenced', ctx=ast.Store())]
        attrs = [n.attr for n in ast.walk(node) if is_attr_on_self(n)]
        value = ast.Tuple(elts=[ast.Str(s=attr) for attr in attrs], ctx=ast.Load())
        return [node, ast.Assign(targets=targets, value=value)]

然后我们不需要直接使用import来加载我们的模块,而是需要一些额外的样板来填充我们的NodeTransformer

filename = 'program.py'
parsed = ast.parse(open(filename).read())
with_references = RecordReferencesTransformer().visit(parsed)
ast.fix_missing_locations(with_references)
exec compile(with_references, filename, 'exec')

print A.m.self_attributes_referenced
a = A()
a.m()

输出:

('x', 'y')
3

实施self_methods_referenced留给读者作为练习。

最后,program.py来源:

class A(object):
    x, y  = 1, 2
    def m(self):
        print self.x + self.y