Python: Using inspection to view the parameters of a function

python-logoThe ability to use introspection to dynamically determine the current code context and frame/stack can be a powerful tool for a developer.

Introspection can be applied for debugging, logging, metrics collection, or method overloading based on type.  I will show a simple example of its usage in this article.

Simple Example

Let’s use a simple HelloWorld function that takes an single optional parameter like below:

def show_hello_world_basic(name="World"):
  print("Hello {}!".format(name))

Using the standard inspect module, we can pull the current frame and argument values.

def show_hello_world_basic(name="World"):

  # gets the current frame and examines args
  myframe = inspect.currentframe()
  args,_,_,values = inspect.getargvalues(myframe)

  # prints function name
  funcname = myframe.f_code.co_name
  print("function {}()".format(funcname))

  # prints simple function arguments
  for i in (args if not args is None else []):
    print("\t{}={}".format(i,values[i]))

  # prints greeting
  print("Hello {}!".format(name))

Which would show us the argument name and values (name=World), before actually printing the message.

function show_hello_world_basic()
     name=World
Hello World!

Extending this logic, we can pull not only the simple arguments, but also positional varargs and keywords varargs.

Sample Program

I have uploaded inspect_func_test.py to github, which you can use to test the more advanced cases using methods with variable args and kwargs.  By placing the following line into a method:

inspect_simple(inspect.currentframe())

You can have it call out to the ‘inspect_simple()’ helper function which shows all the arguments and values passed into a function.

def inspect_simple(frame):
  # pull tuple from frame
  args,args_paramname,kwargs_paramname,values = inspect.getargvalues(frame)

  # stack param could be used to pull function name
  print("function {}()".format(funcname))

  # show static parameters
  for i in (args if not args is None else []):
    print("\t{}={}".format(i,values[i]))

  # show positional varargs
  if args_paramname is not None:
    varglist = values[args_paramname]
    for v in (varglist if not varglist is None else []):
      print("\t*{}={}".format(args_paramname,v))

  # show named varargs
  if kwargs_paramname is not None:
    varglist = values[kwargs_paramname]
    for k in (sorted(varglist) if not varglist is None else []):
      print("\t*{} {}={}".format(kwargs_paramname,k,varglist[k]))

 

If you want to take this to the next level, read my article on using the @ “pie” syntax and custom decorators to inspect function arguments.

 

REFERENCE

python ref, inspect

stackoverflow, showing function name and param name/value pairs

saltycrane, var args

markmiyashita, basic explanation of *args and **kwargs

stefaanlippens, get current function name from stack

programcreek, usage of inspect.CO_VARARGS

realpython, primer on python decorators capturing args kwargs

stackoverflow, performance tradeoff for inspect

 

NOTES

generate help from docstring

pydoc inspect_func_test.py

do PEP8 style check

pylint3 inspect_func_test.py

make PEP8 style fixes automatically, inline and allow longer lines

python -m pip install autopep8
autopep8 --max-line-length=120 -i inspect_func_test.py
python -m pip install pycodestyle
pycodestyle --max-line-length=120 -i inspect_func_test.py