Skip to the content
Fabian Lee : Software EngineerFabian Lee : Software Engineer
Cloud Operations and Development
  • Monitoring
  • Logging
  • Containers
  • Python

Python: Using a custom decorator to inspect function arguments

September 22, 2019
Categories: Python

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.

Building on my earlier article on the basics of introspection, I will now show how to inject custom logic into a function by using the @ “pie” syntax and a custom decorator.

Pie syntax

We want to be able to decorate any method with introspection logic.  To accomplish that we will be using the pie syntax (@).

Below is an example of adding our custom decorator showargs_decorator to the simple function named show_math_result.

@showargs_decorator
def show_math_result(a,b,showLower=True):
  opDisplay = "plus" if showLower else "PLUS"
  print("{} {} {} = {}".format(a, op_display, b, a + b))
  return a+b

The idea in this article is to write our showargs_decorator in a generic enough way that we can decorate any function with this logic.

Custom Decorator

Our custom decorator function is shown below.  It follows the basic template, returning the callable wrapper at the end.

# custom decorator
def showargs_decorator(func):

    # updates special attributes e.g. __name__,__doc__
    @functools.wraps(func)
    def wrapper(*args, **kwargs):

      # call custom inspection logic
      inspect_decorator(func,args,kwargs)

      # calls original function
      func(*args, **kwargs)

    # matches name of inner function
    return wrapper

It uses the variable positional and keyword arguments (*args,**kwargs) so that it can decorate a function with any number of arguments.   We insert ourselves into the function logic by calling out to inspect_decorator, a method we will write and described in the next section.

The functools.wrap updates the double underscore internal variables like function __name__  so it reports properly in the original function.

Custom introspection logic

Our inspect_decorator method uses the original function’s argument specifications to retrieve the descriptions of the arguments that are expected, and marries that with the values passed in *args and **kwargs.

def inspect_decorator(func,args,kwargs):
  funcname = func.__name__
  print("function {}()".format(funcname))
  
  # get description of function params expected
  argspec = inspect.getargspec(func)

  # go through each position based argument        
  counter = 0
  if argspec.args and type(argspec.args is list):
    for arg in args:
      # when you run past the formal positional arguments
      try:
        print(str(argspec.args[counter]) + "=" + str(arg))
        counter+=1
      except IndexError as e:
        # then fallback to using the positional varargs name
        if argspec.varargs:
          varargsname = argspec.varargs
          print("*" + varargsname + "=" + str(arg))
        pass

  # finally show the named varargs
  if argspec.keywords:
    kwargsname = argspec.keywords
    for k,v in kwargs.items():
      print("**" + kwargsname + " " + k + "=" + str(v))

The basic idea is that we get the functions description of its expected parameters using inspect.getargspec, then we map it to the values actually sent to the function (*args and **kwargs).

Sample Program

I have uploaded inspect_func_test_decorator.py to github, which you can use to see the decorator used against functions with varying formal parameters, as well as variable positional and keyword arguments.

 

 

REFERENCES

realpython, decorators and usage

python.org, decorators reference

stackoverflow, getting function signature py2 versus py3

thecodeship, writing decorators

artima, intro to decorators

artima, more advanced decorator use with decorator args

programiz, explanation of decorator being callable returning callable with syntactic sugar

 

Categories: Python Tags: decorator, getargspec, inspect, introspection, metadata, pie, python

Post navigation

← Python: Using inspection to view the parameters of a function
Docker: Installing Docker CE on Ubuntu bionic 18.04 →
© 2025 Fabian Lee : Software Engineer