Python Inspect Module and its Applications With Examples

There may be a situation where you may require a detailed breakdown of a particular function from a Python module or maybe the class module itself. Your initial reaction would be to read pages and pages of documentation or look through the module’s source code through external references. What if I told you this problem could be fixed within Python using a inspect module?

Python’s inspect the module provides in-built functions for fetching programmatical information on live objects, including modules, classes, instances, functions, and methods.

Why do we need this Module?

We can use the functions in this module to obtain the original source code for a particular function, display the arguments to a method on the stack, and extract the type of information you would require for producing library documentation for your own source code.

Let’s go ahead and look into the module ourselves. I recommend you try following along using our Online Python Interpreter.

Importing the Module

This standard library module has existed since Python 2 under the Python Runtime Services category and can be imported by running the following line.

import inspect

Displaying the Contents of a Python Object

A crucial function of this module would be that of inspect.getmembers(). It provides an insight into all the members of an object in pairs according to their names. All the pairs are presented in a Python List format. Let’s look at the code below.

import requests
import inspect

# Creating a response object 
sampleResponse = requests.get("http://httpbin.org/ip")  # provides IP address

# retrieving the members of the object "sampleResponse"
inspect.getmembers(sampleResponse)

##### Sample Output #####
'''
[('__attrs__',
  ['_content',
   'status_code',
   'headers',
   'url',
   'history',
   'encoding',
   'reason',
   'cookies',
   'elapsed',
   'request']),
 ('__bool__', <bound method Response.__bool__ of <Response [200]>>),
 ('__class__', requests.models.Response),
 ('__delattr__',
  <method-wrapper '__delattr__' of Response object at 0x7f560fdfee10>),
 ('__dict__',
  {'_content': b'{\n  "origin": "35.223.57.112"\n}\n',
   '_content_consumed': True,
   '_next': None,
...
...
...
...
...
 ('url', 'http://httpbin.org/ip')]
'''

NOTE: The above output is just a snippet from a more enormous output dump. Please try running the command here for the complete output.

The output consists of a list of tuples providing a complete view of all the members in our sampleRequest object. Let’s look at this beginning section of our output to understand better what it represents.

'''
('__attrs__',   -> name of the property
  ['_content',                  
   'status_code',            
   'headers',                     
   'url',                               
   'history',                  values
   'encoding',
   'reason',
   'cookies',                    
   'elapsed',                    
   'request'])                   
'''

This is a property present in the object by the name of __attrs__. The values belonging to the property are directly below in a list format. Now, check the below sample output on how the methods are represented.

'''
('__bool__', <bound method Response.__bool__ of <Response [200]>>),
 ('__class__', requests.models.Response),
 ('__delattr__',
  <method-wrapper '__delattr__' of Response object at 0x7f560fdfee10>),
'''

This is the way methods of our request object, sampleResponseAre represented.

Verifying Object Types using Inspect

The following functions return a boolean value based on matching a particular type.

FunctionOutput
inspect.ismodule(objectName) True if the object is a Python module
inspect.isclass(objectName)True if the object is a Python class
inspect.ismethod(objectName)True if the object is a Python bound method
inspect.isfunction(objectName)True if the object is a regular Python function or function written from a lambda expression.
inspect.isgeneratorfunction(objectName)True if the object is a Python generator function
inspect.iscoroutinefunction(objectName)True if the object is a coroutine function (defined with async def)
inspect.iscoroutine(objectName)True if the object is created by a coroutine function
inspect.isawaitable(objectName)True if the object can be used with await
inspect.isasyncgenfunction(objectName)True if the object is an asynchronous generator function
inspect.isasyncgen(objectName)True if the object is an asynchronous generator iterator
inspect.istraceback(objectName)True if the object is a traceback
inspect.isframe(objectName)True if the object is a frame
inspect.iscode(objectName)True if the object is a code
inspect.isbuiltin(objectName)True if the object is a built-in function or if it’s a built-in bound method
inspect.isroutine(objectName)True if the object is a :
– User-Defined Function
– Built-In Function
– Method
inspect.isabstract(objectName)True if the object is an abstract base class
inspect.ismethoddescriptor(objectName)True if the object is a method descriptor, but excluding ismethod(), isclass() and isfunction()
inspect.isdatadescriptor(objectName)True if the object is a data descriptor. (If it contains __set__ or __delete__ methods)

Python Inspect ismethod() vs isfunction()

inspect.ismethod()inspect.isfunction()
This function will return True if the provided object is a bound Python method.This function will return True if the provided object is a Python function.

You may notice that there essentially isn’t a difference between a bound method and a plain function in Python. Due to this reason, the concept of “bound methods” was completely removed from the language since Python 3. Every time you reference a class attribute, Python will return a regular function object. It’s best that you avoid using ismethod() or isfunction(). Instead, use inspect.isroutine() which matches both unbound methods and standard Python functions.

Obtaining the Source Code using Inspect

Another valuable application of the module is that you can retrieve the complete source code of a function or class within a few lines of code.

Let’s use this sample function myFunction as an example.

inspect.getsource()

import inspect
def myFunction(x, y):
    """Returns the sum"""
    return x + y

print(inspect.getsource(myFunction))



##### Output #####
'''
def myFunction(x, y):
    """Returns the sum"""
    return x + y

'''

You can also try using inspect.getsourcelines(). This will provide you with the source code that includes a newline character at the end of each line. This will display the Python script line by line.

How to Obtain File Location and Documentation using Python Inspect

Finding Module Location

We can locate a Python module in our system by running this function. Let’s take the same logging module as our example.

inspect.getfile()

import logging
import inspect

# Returns system location of the python logging module
inspect.getfile(logging)

#### Output ####
'/usr/lib/python3.7/logging/__init__.py'

Retrieving File Documentation

You can obtain documentation for a specific class, function, or module by running the following.

inspect.getdoc()

import logging
import inspect

inspect.getdoc(logging)

#### Output ####
'''
Logging package for Python. Based on PEP 282 and comments thereto in
comp.lang.python.

Copyright (C) 2001-2017 Vinay Sajip. All Rights Reserved.

To use, simply 'import logging' and log away!
'''

Displaying Function Arguments and Return Type

Retrieving Function Arguments

We can use the following functions to display the function signature.

inspect.signature()

import logging
import inspect

# Passing the logging function logging.info to retrieve the function signature
inspect.signature(logging.info)

#### Output ####
'''
<Signature (msg, *args, **kwargs)>
'''

Not only the parameters, but we can also display their types as well by using:

inspect.getfullargspec()

import logging
import inspect
# Passing logging.info to get complete argument specifications
inspect.getfullargspec(logging.info)

#### Output ####
'''
FullArgSpec(args=['msg'], varargs='args', varkw='kwargs', defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
'''

Retrieving Return Type

You can use inspect.signature() it to find the return type of a function.

import inspect

def getName(name: str):
  return name
 
exampleSignature = inspect.signature(getName)
# providing the output in a list while applying .annotation
[type.annotation for type in exampleSignature.parameters.values()] 

##### Output #####
'''
[str]
'''

What is bind in Inspect?

Signature.bind() a method that belongs to the class inspect.Signature() under the inspect module. It looks out for a match between the positional argument and the keyword argument in a function signature. Upon matching, it returns the function inspect.BoundArguments() or a TypeError exception if failed to do so.

A similar method is present within the same class, which mimics the former function. The only key difference is that it need not require all arguments to match.

Determining a Generator’s State using Inspect

The final application for this module which we will be looking at, is finding a Python generator’s state. Check out the code below.

import inspect

# Defining a simple generator which prints the values 0,1,2,3, and 4
def sampleGen():
     for value in range(5):
          yield value

gen1 = sampleGen()

We have successfully created a generator and now let’s see what happens if we pass it into inspect.getgeneratorstate().

import inspect

# Defining a simple generator which prints the values 0,1,2,3, and 4
def sampleGen():
     for value in range(5):
          yield value

gen1 = sampleGen()
inspect.getgeneratorstate(gen1)

##### Output #####
'''
GEN_CREATED
'''

The generator has been newly created. Not a single iteration has taken place as of now. Let’s make the generator complete a few iterations and re-run inspect.getgeneratorstate(gen1)

import inspect 

# Defining a simple generator which prints the values 0,1,2,3, and 4
def sampleGen():
     for value in range(5):
          yield value

gen1 = sampleGen()
next(gen1) # re-running this line will give the consecutive value until range limit
inspect.getgeneratorstate(gen1)

##### Output ####
'''
GEN_SUSPENDED
'''

GEN_SUSPENDED indicates the generator has run and suspended itself after reaching yield value.

Let’s see what happens if we run the same function after the generator’s final iteration.

import inspect

# Defining a simple generator which prints the values 0,1,2,3, and 4
def sampleGen():
     for value in range(5):
          yield value

gen1 = sampleGen()
next(gen1) # re-running this line multiple times until StopIteration exception
inspect.getgeneratorstate(gen1)

##### Output #####
'''
GEN_CLOSED
'''

At this point, the generator loses functionality. It has completed its task of producing values within the range of 5. Hence, GEN_CLOSED.

Python Inspect vs Python Traceback

inspecttraceback
inspect provides in-built functions for fetching programmatical information on live objects, including modules, classes, instances, functions, and methods.A traceback is a report which contains all the function calls made in your code at a specific scope.
inspect.trace() provides a list of frame records for the stack between the current frame and the frame in which an exception currently being handled was raised. The first entry in the list provides the caller information, and the last entry indicates where the exception was raised by Python.The traceback module in Python provides the ability to extract, format, and print tracebacks of programs. It exactly mimics the behavior of a Python interpreter when it prints a traceback.

FAQs on Python Inspect Module

Why use Python Inspect for module, class, or method information if we can simply pass help()?

help() cannot provide the complete list of properties and methods and their values. Then, there’s the inability to obtain source code. help() only provides textual descriptions whereas inspect provides detailed programmatical information.

What does Python inspect.getmro() do?

It returns a tuple of the class’s base classes, including the class itself, in method resolution order. There is no repetition of class names. Note that the method resolution order depends on the class’s type. Unless a user-defined data type is being used, the class we passed into the function will always be the first element of the tuple.

What is the use of Python inspect f_back?

f_back provides you with the succeeding outer frame object. Let’s say you want to retrieve a function caller’s information. You can use inspect.currentframe().f_back and assign it to “var” to retrieve the frame with relevant information. Then pass inspect.getframeinfo(var) to display the frame’s contents. Thereby providing you with details on the file-caller and at which lines it was called.

Conclusion

We have looked at an old but very much a gold standard Python module, inspect. Modern Python IDEs may cover specific use-cases, but its ability to provide very programmatical and technical insights to various aspects of our Python code makes it a one-of-a-kind module.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments