Inspecting code in Python
Lisp users would laugh, since they have macros, but Python supports some basic code inspection and modification.
Consider the following pieces of code:
margin = lambda v: 1 - v['cost'] / v['sales']
What if you wanted another function that lists all the dictionary indices used in the function? That is, you wanted to extract cost
and sales
?
This is a real-life problem I encountered this morning. I have 100 functions, each defining a metric. For example,
lambda v: v['X'] + v['Y']
lambda v: v['X'] - v['Z']
lambda v: (v['X'] + v['Y']) / v['Z']
- …
I had to plot the functions, as well as each of the corresponding elements (‘X’, ‘Y’ and ‘Z’) in the formula.
Two options. One: along with each formula, maintain a list of the elements used. Two: figure it out automatically.
Each function has a func_code
attribute. So, when you take
margin = lambda v: 1 - v['cost'] / v['sales']
margin.func_code
is a “code object”. This has a bunch of interesting attributes, one of which is co_consts
>>> margin.func_code.co_consts
(None, 1, 'cost', 'sales')
There — I just pick the strings out of that list and we’re done (for simple functions at least.)
Check out http://docs.python.org/reference/datamodel.html and search for func_
— you’ll find a number of interesting things you can do with functions, such as
- Finding and changing the default parameters
- Accessing the global variables of the namespace where the function was defined (!)
- Replacing the function code with new code
Also search for co_
— you’ll find some even more interesting things you can do with the code:
- Find all local variable names
- Find all constants used in the code
- Find the filename and line number where the code was compiled from
Python also comes with a disassembly module dis. A look at its source is instructive.