excuse my beeing criptic (you wrote: "I have some troubles
understanding what you mean") but I coudn't to go on too long.
Now I can conclude my speech...
When I was younger I transformed a big Clipper program in
simil-C in order to apply cflow... and I succeeded...
but Clipper wasn't OO!
To better explain I must introduce cflow...
/* whoami.c - a simple implementation of whoami utility */
int who_am_i (void) #~13
struct passwd *pw;
char *user = NULL;
pw = getpwuid (geteuid ()); #~18
user = pw->pw_name;
else if ((user = getenv ("USER")) == NULL) #~21
fprintf (stderr, "I don't know!\n"); #~23
printf ("%s\n", user);
int main (int argc, char **argv) #~31
if (argc > 1)
fprintf (stderr, "usage: whoami\n"); #~35
return who_am_i (); #~38
Running `cflow' produces the following output:
$ cflow whoami.c
main() <int main (int argc,char **argv) #~:31>:
~ all C programs start with main()
+-- fprintf() ~ called from #~35
+-- who_am_i() <int who_am_i (void) #~13 ~ #~38
+-- getpwuid() ~ #~18
+-- geteuid() ~ #~18
+-- getenv() ~ #~21
+-- fprintf() ~ #~23
+-- printf() ~ #~26
This is a direct call graph showing "caller--callee" dependencies
Now let us analyse a python script...In this case the presence of
OO constructs makes much more difficult to obtain a call graph...
(at least for me!).
To better show the problems, I take for example a very small script.
# from: http://www.freenetpages.co.uk/hp/alan.gauld/tutclass.htm
# w/ some adds up
def __init__(self, val):
self.val = val
print "hello, my value is:", self.val
# create two instances
a = C(27)
b = C(42)
def E(): #~15
print 'hello '+ F()
def F(): #~18
return raw_input('Addressed to ') #~19
def G(): #~21
print 'Hello world'
# first try sending messages to the instances
# hello, my value is 27
# hello, my value is 42
# now call the method explicitly via the class
# hello, my value is 27
# Addressing functions
""" call tree w/o classes and objects:
E() #~15 called from #~35
+-- F() #~18 16
+-- raw_input('Addressed to ') # called from 19
+-- G() #~21 18
G() #~21 36
Beeing the script so small, the above call tree can be
build up by hand, but in every case in am not able to
incorporate classes, instances and method calls...
Instead, if I move "all" the OO references to a module
(for example m2instancesOO.py saved in the same dir as the
part w/o OO)
I could fictitiously trasform OOP in "procedural" programming,
getting therefore only function definitions and calls.
It not an easy task... therefore I called help.
in my experience, I am convinced that call trees (together with xref)
are the main tools to understand not trivial python programs.
Instead of using debuggers, with these tools (and with the
judicious use of trace) you can solve any bug and besides that
acquire a better understanding of the program.
Another advantage of moving OO stuff to modules is the "sharp
increase in re-usability of code...
In my understanding modules are the python's implementation
of libraries very much used by other languages.