假设:
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']
答案 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