Say that I have a function like the following:
def eggs(a,b,c):
if c.foo:
return a + b.bar
else:
return c.spam
I'd like to have a higher order function capable of introspecting the function passed and retrieve what members of an argument are mentioned inside the code via the dot syntax, with the following behavior:
>>> member_inspector(eggs, 'c')
('foo','spam')
>>> member_inspector(eggs, 'b')
('bar')
>>> member_inspector(eggs, 'a')
()
Can this be done? How?
1 Answer 1
Here's a basic version:
import inspect
from textwrap import dedent
import ast
def member_inspector(f, var):
source = dedent(inspect.getsource(f))
module = ast.parse(source)
func = module.body[0]
result = []
for stmt in func.body:
for node in ast.walk(stmt):
if (isinstance(node, ast.Attribute) and
isinstance(node.value, ast.Name) and
node.value.id == var):
result.append(node.attr)
return result
answered May 2, 2018 at 12:30
Alex Hall
36.2k5 gold badges63 silver badges98 bronze badges
Sign up to request clarification or add additional context in comments.
1 Comment
Aran-Fey
Could I ask you for a bit of explanation, maybe some links to the
ast module docs, and maybe even a "caveats" section? (Doesn't work if the function's source code can't be accessed, doesn't detect attribute access with getattr or vars or __dict__, gets tripped up by assignments like foo = c; c.bar, if the same attribute is accessed twice it's included in the output twice, etc.) Your code is good, but the answer is not.Explore related questions
See similar questions with these tags.
lang-py
getattr(c, 'b' + 'a' + 'r')? Ordef eggs(c, p): getattr(c, p). These examples are only evaluated at runtime and cannot be introspected.foo = cand then accessesfoo.spam?member_inspector(eggs, 'c')returns(). I'm not interested in backtracking variable assignments (unless someone comes up with a very simple way to include it as a plus)