I know only one way to complete my task. It is to use globals() and then parse source code. But it seems is very ugly.
I'm not sure what you think parsing source code would do for you here.
If you want to build a dynamic call graph, what you want to do is decorate each function—replace it with a wrapper that does some extra stuff before or after calling the real function. For example:
def wrapper(func):
@functools.wraps
def wrap(*args, **kwargs):
# do stuff to update call graph
return func(*args, **kwargs)
return wrap
g = globals()
for name, value in g.items():
if callable(value):
g[name] = wrapper(value)
Or, maybe more simply (and more flexibly), you might want to use the bdb debugger framework to step through your program and just record the user_call instances.
If you want to build a static call graph, then obviously that comes from the source, but there's no reason to parse it yourself when Python comes with the ast module to do it for you. (You can use inspect.getsource to get the source code to parse.)
globals()and then parse source code." How do you think parsing source code would help? I can't see any solution where that would be useful. But if you can show that, I'll bet I could show you how to replace the parsing with something different.f = open("globals()["__file__"]");and then parse it.globals()["__file__"]gets you the exact same thing as just__file__, soglobalsisn't helping there… Also, you can useinspect.getsourceto read source. Meanwhile, what would you do with the data once you parse it? You can use theastmodule to create a parsed tree out of it, but then what? Are you just looking to create a static call graph—all the functions referenced inmain's body—rather than a dynamic one—all the functions called during an actual run of the program?