The inspect module provides functions for learning about live objects, classes, instances, and methods. The functions in this module can be used to retrieve the original source code for a function, look the arguments to a method on the stack, and extract the sort of information useful for producing library documentation for source code.

Example code


In [ ]:
# %load example.py

def module_level_function(arg1, arg2='default', *args, **kwargs):
    """This function is declared in the module."""
    local_variable = arg1 * 2
    return local_variable


class A(object):
    """The A class."""

    def __init__(self, name):
        self.name = name

    def get_name(self):
        "Returns the name of the instance."
        return self.name


instance_of_a = A('sample_instance')


class B(A):
    """This is the B class.
    It is derived from A.
    """

    # This method is not part of A.
    def do_something(self):
        """Does some work"""

    def get_name(self):
        "Overrides version from A"
        return 'B(' + self.name + ')'

The first kind of introspection probes live objects to learn about them. Use getmembers() to discover the member attributes of object. The types of members that might be returned depend on the type of object scanned. Modules can contain classes and functions; classes can contain methods and attributes; and so on.

The arguments to getmembers() are an object to scan (a module, class, or instance) and an optional predicate function that is used to filter the objects returned. The return value is a list of tuples with two values: the name of the member, and the type of the member. The inspect module includes several such predicate functions with names like ismodule(), isclass(), etc.


In [3]:
import inspect

import example

for name, data in inspect.getmembers(example):
    if name.startswith('__'):
        continue
    print('{} : {!r}'.format(name, data))


A : <class 'example.A'>
B : <class 'example.B'>
instance_of_a : <example.A object at 0x7f5dc06bfc50>
module_level_function : <function module_level_function at 0x7f5dc0717e18>

The predicate argument can be used to filter the types of objects returned.


In [4]:
import inspect

import example

for name, data in inspect.getmembers(example, inspect.isclass):
    print('{} : {!r}'.format(name, data))


A : <class 'example.A'>
B : <class 'example.B'>

Inspecting Classes

Classes are scanned using getmembers() in the same way as modules, though the types of members are different.


In [5]:
import inspect
from pprint import pprint

import example

pprint(inspect.getmembers(example.A), width=65)


[('__class__', <class 'type'>),
 ('__delattr__',
  <slot wrapper '__delattr__' of 'object' objects>),
 ('__dict__',
  mappingproxy({'__dict__': <attribute '__dict__' of 'A' objects>,
                '__doc__': 'The A class.',
                '__init__': <function A.__init__ at 0x7f5dc07178c8>,
                '__module__': 'example',
                '__weakref__': <attribute '__weakref__' of 'A' objects>,
                'get_name': <function A.get_name at 0x7f5dc0717840>})),
 ('__dir__', <method '__dir__' of 'object' objects>),
 ('__doc__', 'The A class.'),
 ('__eq__', <slot wrapper '__eq__' of 'object' objects>),
 ('__format__', <method '__format__' of 'object' objects>),
 ('__ge__', <slot wrapper '__ge__' of 'object' objects>),
 ('__getattribute__',
  <slot wrapper '__getattribute__' of 'object' objects>),
 ('__gt__', <slot wrapper '__gt__' of 'object' objects>),
 ('__hash__', <slot wrapper '__hash__' of 'object' objects>),
 ('__init__', <function A.__init__ at 0x7f5dc07178c8>),
 ('__init_subclass__',
  <built-in method __init_subclass__ of type object at 0xe89748>),
 ('__le__', <slot wrapper '__le__' of 'object' objects>),
 ('__lt__', <slot wrapper '__lt__' of 'object' objects>),
 ('__module__', 'example'),
 ('__ne__', <slot wrapper '__ne__' of 'object' objects>),
 ('__new__',
  <built-in method __new__ of type object at 0x7f5dccd51e80>),
 ('__reduce__', <method '__reduce__' of 'object' objects>),
 ('__reduce_ex__', <method '__reduce_ex__' of 'object' objects>),
 ('__repr__', <slot wrapper '__repr__' of 'object' objects>),
 ('__setattr__',
  <slot wrapper '__setattr__' of 'object' objects>),
 ('__sizeof__', <method '__sizeof__' of 'object' objects>),
 ('__str__', <slot wrapper '__str__' of 'object' objects>),
 ('__subclasshook__',
  <built-in method __subclasshook__ of type object at 0xe89748>),
 ('__weakref__', <attribute '__weakref__' of 'A' objects>),
 ('get_name', <function A.get_name at 0x7f5dc0717840>)]

To find the methods of a class, use the isfunction() predicate. The ismethod() predicate only recognizes bound methods of instances.


In [6]:
import inspect
from pprint import pprint

import example

pprint(inspect.getmembers(example.A, inspect.isfunction))


[('__init__', <function A.__init__ at 0x7f5dc07178c8>),
 ('get_name', <function A.get_name at 0x7f5dc0717840>)]

The output for B includes the override for get_name() as well as the new method, and the inherited init() method implemented in A.


In [7]:
import inspect
from pprint import pprint

import example

pprint(inspect.getmembers(example.B, inspect.isfunction))


[('__init__', <function A.__init__ at 0x7f5dc07178c8>),
 ('do_something', <function B.do_something at 0x7f5dc07177b8>),
 ('get_name', <function B.get_name at 0x7f5dc0717730>)]

Inspecting Instances

Introspecting instances works in the same way as other objects.


In [8]:
import inspect
from pprint import pprint

import example

a = example.A(name='inspect_getmembers')
pprint(inspect.getmembers(a, inspect.ismethod))


[('__init__',
  <bound method A.__init__ of <example.A object at 0x7f5dc06c9cf8>>),
 ('get_name',
  <bound method A.get_name of <example.A object at 0x7f5dc06c9cf8>>)]

Documentation Strings

The docstring for an object can be retrieved with getdoc(). The return value is the doc attribute with tabs expanded to spaces and with indentation made uniform.


In [10]:
import inspect
import example

print('B.__doc__:')
print(example.B.__doc__)
print()
print('getdoc(B):')
print(inspect.getdoc(example.B))


B.__doc__:
This is the B class.
    It is derived from A.
    

getdoc(B):
This is the B class.
It is derived from A.

The second line of the docstring is indented when it is retrieved through the attribute directly, but moved to the left margin by getdoc().

In addition to the actual docstring, it is possible to retrieve the comments from the source file where an object is implemented, if the source is available. The getcomments() function looks at the source of the object and finds comments on lines preceding the implementation.


In [11]:
import inspect
import example

print(inspect.getcomments(example.B.do_something))


# This method is not part of A.

Retrieving Source

If the .py file is available for a module, the original source code for the class or method can be retrieved using getsource() and getsourcelines().


In [13]:
import inspect
import example

print(inspect.getsource(example.A))


class A(object):
    """The A class."""

    def __init__(self, name):
        self.name = name

    def get_name(self):
        "Returns the name of the instance."
        return self.name

To retrieve the source for a single method, pass the method reference to getsource().


In [14]:
import inspect
import example

print(inspect.getsource(example.A.get_name))


    def get_name(self):
        "Returns the name of the instance."
        return self.name

Use getsourcelines() instead of getsource() to retrieve the lines of source split into individual strings.


In [15]:
import inspect
import pprint
import example

pprint.pprint(inspect.getsourcelines(example.A.get_name))


(['    def get_name(self):\n',
  '        "Returns the name of the instance."\n',
  '        return self.name\n'],
 14)

Method and Function Signatures

In addition to the documentation for a function or method, it is possible to ask for a complete specification of the arguments the callable takes, including default values. The signature() function returns a Signature instance containing information about the arguments to the function.


In [16]:
import inspect
import example

sig = inspect.signature(example.module_level_function)
print('module_level_function{}'.format(sig))

print('\nParameter details:')
for name, param in sig.parameters.items():
    if param.kind == inspect.Parameter.POSITIONAL_ONLY:
        print('  {} (positional-only)'.format(name))
    elif param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:
        if param.default != inspect.Parameter.empty:
            print('  {}={!r}'.format(name, param.default))
        else:
            print('  {}'.format(name))
    elif param.kind == inspect.Parameter.VAR_POSITIONAL:
        print('  *{}'.format(name))
    elif param.kind == inspect.Parameter.KEYWORD_ONLY:
        if param.default != inspect.Parameter.empty:
            print('  {}={!r} (keyword-only)'.format(
                name, param.default))
        else:
            print('  {} (keyword-only)'.format(name))
    elif param.kind == inspect.Parameter.VAR_KEYWORD:
        print('  **{}'.format(name))


module_level_function(arg1, arg2='default', *args, **kwargs)

Parameter details:
  arg1
  arg2='default'
  *args
  **kwargs

The function arguments are available through the parameters attribute of the Signature. parameters is an ordered dictionary mapping the parameter names to Parameter instances describing the argument. In this example, the first argument to the function, arg1, does not have a default value, while arg2 does.

The Signature for a function can be used by decorators or other functions to validate inputs, provide different defaults, etc. Writing a suitably generic and reusable validation decorator has one special challenge, though, because it can be complicated to match up incoming arguments with their names for functions that accept a combination of named and positional arguments. The bind() and bind_partial() methods provide the necessary logic to handle the mapping. They return a BoundArguments instance populated with the arguments associated with the names of the arguments of a specified function.


In [17]:
import inspect
import example

sig = inspect.signature(example.module_level_function)

bound = sig.bind(
    'this is arg1',
    'this is arg2',
    'this is an extra positional argument',
    extra_named_arg='value',
)

print('Arguments:')
for name, value in bound.arguments.items():
    print('{} = {!r}'.format(name, value))

print('\nCalling:')
print(example.module_level_function(*bound.args, **bound.kwargs))


Arguments:
arg1 = 'this is arg1'
arg2 = 'this is arg2'
args = ('this is an extra positional argument',)
kwargs = {'extra_named_arg': 'value'}

Calling:
this is arg1this is arg1

Class Hierarchies

inspect includes two methods for working directly with class hierarchies. The first, getclasstree(), creates a tree-like data structure based on the classes it is given and their base classes. Each element in the list returned is either a tuple with a class and its base classes, or another list containing tuples for subclasses.


In [18]:
import inspect
import example


class C(example.B):
    pass


class D(C, example.A):
    pass


def print_class_tree(tree, indent=-1):
    if isinstance(tree, list):
        for node in tree:
            print_class_tree(node, indent + 1)
    else:
        print('  ' * indent, tree[0].__name__)
    return


if __name__ == '__main__':
    print('A, B, C, D:')
    print_class_tree(inspect.getclasstree(
        [example.A, example.B, C, D])
    )


A, B, C, D:
 object
   A
     D
     B
       C
         D

The output from this example is the tree of inheritance for the A, B, C, and D classes. D appears twice, since it inherits from both C and A.

If getclasstree() is called with unique set to a true value, the output is different.


In [20]:
import inspect
import example

print_class_tree(inspect.getclasstree(
    [example.A, example.B, C, D],
    unique=True,
))


 object
   A
     B
       C
         D

Method Resolution Order

The other function for working with class hierarchies is getmro(), which returns a tuple of classes in the order they should be scanned when resolving an attribute that might be inherited from a base class using the Method Resolution Order (MRO). Each class in the sequence appears only once.


In [21]:
import inspect
import example


class C(object):
    pass


class C_First(C, example.B):
    pass


class B_First(example.B, C):
    pass


print('B_First:')
for c in inspect.getmro(B_First):
    print('  {}'.format(c.__name__))
print()
print('C_First:')
for c in inspect.getmro(C_First):
    print('  {}'.format(c.__name__))


B_First:
  B_First
  B
  A
  C
  object

C_First:
  C_First
  C
  B
  A
  object

The Stack and Frames

In addition to introspection of code objects, inspect includes functions for inspecting the runtime environment while a program is being executed. Most of these functions work with the call stack, and operate on call frames. Frame objects hold the current execution context, including references to the code being run, the operation being executed, as well as the values of local and global variables. Typically such information is used to build tracebacks when exceptions are raised. It can also be useful for logging or when debugging programs, since the stack frames can be interrogated to discover the argument values passed into the functions.

currentframe() returns the frame at the top of the stack (for the current function).


In [22]:
import inspect
import pprint


def recurse(limit, keyword='default', *, kwonly='must be named'):
    local_variable = '.' * limit
    keyword = 'changed value of argument'
    frame = inspect.currentframe()
    print('line {} of {}'.format(frame.f_lineno,
                                 frame.f_code.co_filename))
    print('locals:')
    pprint.pprint(frame.f_locals)
    print()
    if limit <= 0:
        return
    recurse(limit - 1)
    return local_variable

if __name__ == '__main__':
    recurse(2)


line 10 of <ipython-input-22-b4ab6a1b61fd>
locals:
{'frame': <frame object at 0x7f5dc071bb88>,
 'keyword': 'changed value of argument',
 'kwonly': 'must be named',
 'limit': 2,
 'local_variable': '..'}

line 10 of <ipython-input-22-b4ab6a1b61fd>
locals:
{'frame': <frame object at 0x15a8bb8>,
 'keyword': 'changed value of argument',
 'kwonly': 'must be named',
 'limit': 1,
 'local_variable': '.'}

line 10 of <ipython-input-22-b4ab6a1b61fd>
locals:
{'frame': <frame object at 0x7f5db401b268>,
 'keyword': 'changed value of argument',
 'kwonly': 'must be named',
 'limit': 0,
 'local_variable': ''}

Using stack(), it is also possible to access all of the stack frames from the current frame to the first caller. This example is similar to the one shown earlier, except it waits until reaching the end of the recursion to print the stack information.


In [23]:
import inspect
import pprint


def show_stack():
    for level in inspect.stack():
        print('{}[{}]\n  -> {}'.format(
            level.frame.f_code.co_filename,
            level.lineno,
            level.code_context[level.index].strip(),
        ))
        pprint.pprint(level.frame.f_locals)
        print()


def recurse(limit):
    local_variable = '.' * limit
    if limit <= 0:
        show_stack()
        return
    recurse(limit - 1)
    return local_variable


if __name__ == '__main__':
    recurse(2)


<ipython-input-23-70367c7817ec>[6]
  -> for level in inspect.stack():
{'level': FrameInfo(frame=<frame object at 0x7f5dc06c43f8>, filename='<ipython-input-23-70367c7817ec>', lineno=6, function='show_stack', code_context=['    for level in inspect.stack():\n'], index=0)}

<ipython-input-23-70367c7817ec>[19]
  -> show_stack()
{'limit': 0, 'local_variable': ''}

<ipython-input-23-70367c7817ec>[21]
  -> recurse(limit - 1)
{'limit': 1, 'local_variable': '.'}

<ipython-input-23-70367c7817ec>[21]
  -> recurse(limit - 1)
{'limit': 2, 'local_variable': '..'}

<ipython-input-23-70367c7817ec>[26]
  -> recurse(2)
{'A': <class '__main__.A'>,
 'B': <class '__main__.B'>,
 'B_First': <class '__main__.B_First'>,
 'C': <class '__main__.C'>,
 'C_First': <class '__main__.C_First'>,
 'D': <class '__main__.D'>,
 'In': ['',
        '\n'
        "def module_level_function(arg1, arg2='default', *args, **kwargs):\n"
        '    """This function is declared in the module."""\n'
        '    local_variable = arg1 * 2\n'
        '    return local_variable\n'
        '\n'
        '\n'
        'class A(object):\n'
        '    """The A class."""\n'
        '\n'
        '    def __init__(self, name):\n'
        '        self.name = name\n'
        '\n'
        '    def get_name(self):\n'
        '        "Returns the name of the instance."\n'
        '        return self.name\n'
        '\n'
        '\n'
        "instance_of_a = A('sample_instance')\n"
        '\n'
        '\n'
        'class B(A):\n'
        '    """This is the B class.\n'
        '    It is derived from A.\n'
        '    """\n'
        '\n'
        '    # This method is not part of A.\n'
        '    def do_something(self):\n'
        '        """Does some work"""\n'
        '\n'
        '    def get_name(self):\n'
        '        "Overrides version from A"\n'
        "        return 'B(' + self.name + ')'",
        "get_ipython().magic('load example.py')",
        'import inspect\n'
        '\n'
        'import example\n'
        '\n'
        'for name, data in inspect.getmembers(example):\n'
        "    if name.startswith('__'):\n"
        '        continue\n'
        "    print('{} : {!r}'.format(name, data))",
        'import inspect\n'
        '\n'
        'import example\n'
        '\n'
        'for name, data in inspect.getmembers(example, inspect.isclass):\n'
        "    print('{} : {!r}'.format(name, data))",
        'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        'pprint(inspect.getmembers(example.A), width=65)',
        'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        'pprint(inspect.getmembers(example.A, inspect.isfunction))',
        'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        'pprint(inspect.getmembers(example.B, inspect.isfunction))',
        'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        "a = example.A(name='inspect_getmembers')\n"
        'pprint(inspect.getmembers(a, inspect.ismethod))',
        'The docstring for an object can be retrieved with getdoc(). The '
        'return value is the __doc__ attribute with tabs expanded to spaces '
        'and with indentation made uniform.',
        'import inspect\n'
        'import example\n'
        '\n'
        "print('B.__doc__:')\n"
        'print(example.B.__doc__)\n'
        'print()\n'
        "print('getdoc(B):')\n"
        'print(inspect.getdoc(example.B))',
        'import inspect\n'
        'import example\n'
        '\n'
        'print(inspect.getcomments(example.B.do_something))',
        'import inspect\nimport example\n\nprint(inspect.getcomments(example))',
        'import inspect\nimport example\n\nprint(inspect.getsource(example.A))',
        'import inspect\n'
        'import example\n'
        '\n'
        'print(inspect.getsource(example.A.get_name))',
        'import inspect\n'
        'import pprint\n'
        'import example\n'
        '\n'
        'pprint.pprint(inspect.getsourcelines(example.A.get_name))',
        'import inspect\n'
        'import example\n'
        '\n'
        'sig = inspect.signature(example.module_level_function)\n'
        "print('module_level_function{}'.format(sig))\n"
        '\n'
        "print('\\nParameter details:')\n"
        'for name, param in sig.parameters.items():\n'
        '    if param.kind == inspect.Parameter.POSITIONAL_ONLY:\n'
        "        print('  {} (positional-only)'.format(name))\n"
        '    elif param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:\n'
        '        if param.default != inspect.Parameter.empty:\n'
        "            print('  {}={!r}'.format(name, param.default))\n"
        '        else:\n'
        "            print('  {}'.format(name))\n"
        '    elif param.kind == inspect.Parameter.VAR_POSITIONAL:\n'
        "        print('  *{}'.format(name))\n"
        '    elif param.kind == inspect.Parameter.KEYWORD_ONLY:\n'
        '        if param.default != inspect.Parameter.empty:\n'
        "            print('  {}={!r} (keyword-only)'.format(\n"
        '                name, param.default))\n'
        '        else:\n'
        "            print('  {} (keyword-only)'.format(name))\n"
        '    elif param.kind == inspect.Parameter.VAR_KEYWORD:\n'
        "        print('  **{}'.format(name))",
        'import inspect\n'
        'import example\n'
        '\n'
        'sig = inspect.signature(example.module_level_function)\n'
        '\n'
        'bound = sig.bind(\n'
        "    'this is arg1',\n"
        "    'this is arg2',\n"
        "    'this is an extra positional argument',\n"
        "    extra_named_arg='value',\n"
        ')\n'
        '\n'
        "print('Arguments:')\n"
        'for name, value in bound.arguments.items():\n'
        "    print('{} = {!r}'.format(name, value))\n"
        '\n'
        "print('\\nCalling:')\n"
        'print(example.module_level_function(*bound.args, **bound.kwargs))',
        'import inspect\n'
        'import example\n'
        '\n'
        '\n'
        'class C(example.B):\n'
        '    pass\n'
        '\n'
        '\n'
        'class D(C, example.A):\n'
        '    pass\n'
        '\n'
        '\n'
        'def print_class_tree(tree, indent=-1):\n'
        '    if isinstance(tree, list):\n'
        '        for node in tree:\n'
        '            print_class_tree(node, indent + 1)\n'
        '    else:\n'
        "        print('  ' * indent, tree[0].__name__)\n"
        '    return\n'
        '\n'
        '\n'
        "if __name__ == '__main__':\n"
        "    print('A, B, C, D:')\n"
        '    print_class_tree(inspect.getclasstree(\n'
        '        [example.A, example.B, C, D])\n'
        '    )',
        'import inspect\n'
        'import example\n'
        'from inspect_getclasstree import *\n'
        '\n'
        'print_class_tree(inspect.getclasstree(\n'
        '    [example.A, example.B, C, D],\n'
        '    unique=True,\n'
        '))',
        'import inspect\n'
        'import example\n'
        '\n'
        'print_class_tree(inspect.getclasstree(\n'
        '    [example.A, example.B, C, D],\n'
        '    unique=True,\n'
        '))',
        'import inspect\n'
        'import example\n'
        '\n'
        '\n'
        'class C(object):\n'
        '    pass\n'
        '\n'
        '\n'
        'class C_First(C, example.B):\n'
        '    pass\n'
        '\n'
        '\n'
        'class B_First(example.B, C):\n'
        '    pass\n'
        '\n'
        '\n'
        "print('B_First:')\n"
        'for c in inspect.getmro(B_First):\n'
        "    print('  {}'.format(c.__name__))\n"
        'print()\n'
        "print('C_First:')\n"
        'for c in inspect.getmro(C_First):\n'
        "    print('  {}'.format(c.__name__))",
        '\n'
        'import inspect\n'
        'import pprint\n'
        '\n'
        '\n'
        "def recurse(limit, keyword='default', *, kwonly='must be named'):\n"
        "    local_variable = '.' * limit\n"
        "    keyword = 'changed value of argument'\n"
        '    frame = inspect.currentframe()\n'
        "    print('line {} of {}'.format(frame.f_lineno,\n"
        '                                 frame.f_code.co_filename))\n'
        "    print('locals:')\n"
        '    pprint.pprint(frame.f_locals)\n'
        '    print()\n'
        '    if limit <= 0:\n'
        '        return\n'
        '    recurse(limit - 1)\n'
        '    return local_variable\n'
        '\n'
        "if __name__ == '__main__':\n"
        '    recurse(2)',
        'import inspect\n'
        'import pprint\n'
        '\n'
        '\n'
        'def show_stack():\n'
        '    for level in inspect.stack():\n'
        "        print('{}[{}]\\n  -> {}'.format(\n"
        '            level.frame.f_code.co_filename,\n'
        '            level.lineno,\n'
        '            level.code_context[level.index].strip(),\n'
        '        ))\n'
        '        pprint.pprint(level.frame.f_locals)\n'
        '        print()\n'
        '\n'
        '\n'
        'def recurse(limit):\n'
        "    local_variable = '.' * limit\n"
        '    if limit <= 0:\n'
        '        show_stack()\n'
        '        return\n'
        '    recurse(limit - 1)\n'
        '    return local_variable\n'
        '\n'
        '\n'
        "if __name__ == '__main__':\n"
        '    recurse(2)'],
 'Out': {},
 '_': '',
 '__': '',
 '___': '',
 '__builtin__': <module 'builtins' (built-in)>,
 '__builtins__': <module 'builtins' (built-in)>,
 '__doc__': 'Automatically created module for IPython interactive environment',
 '__loader__': None,
 '__name__': '__main__',
 '__package__': None,
 '__spec__': None,
 '_dh': ['/home/scott/github/Python-3-Module-of-the-Week/language_tool'],
 '_i': '\n'
       'import inspect\n'
       'import pprint\n'
       '\n'
       '\n'
       "def recurse(limit, keyword='default', *, kwonly='must be named'):\n"
       "    local_variable = '.' * limit\n"
       "    keyword = 'changed value of argument'\n"
       '    frame = inspect.currentframe()\n'
       "    print('line {} of {}'.format(frame.f_lineno,\n"
       '                                 frame.f_code.co_filename))\n'
       "    print('locals:')\n"
       '    pprint.pprint(frame.f_locals)\n'
       '    print()\n'
       '    if limit <= 0:\n'
       '        return\n'
       '    recurse(limit - 1)\n'
       '    return local_variable\n'
       '\n'
       "if __name__ == '__main__':\n"
       '    recurse(2)',
 '_i1': '\n'
        "def module_level_function(arg1, arg2='default', *args, **kwargs):\n"
        '    """This function is declared in the module."""\n'
        '    local_variable = arg1 * 2\n'
        '    return local_variable\n'
        '\n'
        '\n'
        'class A(object):\n'
        '    """The A class."""\n'
        '\n'
        '    def __init__(self, name):\n'
        '        self.name = name\n'
        '\n'
        '    def get_name(self):\n'
        '        "Returns the name of the instance."\n'
        '        return self.name\n'
        '\n'
        '\n'
        "instance_of_a = A('sample_instance')\n"
        '\n'
        '\n'
        'class B(A):\n'
        '    """This is the B class.\n'
        '    It is derived from A.\n'
        '    """\n'
        '\n'
        '    # This method is not part of A.\n'
        '    def do_something(self):\n'
        '        """Does some work"""\n'
        '\n'
        '    def get_name(self):\n'
        '        "Overrides version from A"\n'
        "        return 'B(' + self.name + ')'",
 '_i10': 'import inspect\n'
         'import example\n'
         '\n'
         "print('B.__doc__:')\n"
         'print(example.B.__doc__)\n'
         'print()\n'
         "print('getdoc(B):')\n"
         'print(inspect.getdoc(example.B))',
 '_i11': 'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getcomments(example.B.do_something))',
 '_i12': 'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getcomments(example))',
 '_i13': 'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getsource(example.A))',
 '_i14': 'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getsource(example.A.get_name))',
 '_i15': 'import inspect\n'
         'import pprint\n'
         'import example\n'
         '\n'
         'pprint.pprint(inspect.getsourcelines(example.A.get_name))',
 '_i16': 'import inspect\n'
         'import example\n'
         '\n'
         'sig = inspect.signature(example.module_level_function)\n'
         "print('module_level_function{}'.format(sig))\n"
         '\n'
         "print('\\nParameter details:')\n"
         'for name, param in sig.parameters.items():\n'
         '    if param.kind == inspect.Parameter.POSITIONAL_ONLY:\n'
         "        print('  {} (positional-only)'.format(name))\n"
         '    elif param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:\n'
         '        if param.default != inspect.Parameter.empty:\n'
         "            print('  {}={!r}'.format(name, param.default))\n"
         '        else:\n'
         "            print('  {}'.format(name))\n"
         '    elif param.kind == inspect.Parameter.VAR_POSITIONAL:\n'
         "        print('  *{}'.format(name))\n"
         '    elif param.kind == inspect.Parameter.KEYWORD_ONLY:\n'
         '        if param.default != inspect.Parameter.empty:\n'
         "            print('  {}={!r} (keyword-only)'.format(\n"
         '                name, param.default))\n'
         '        else:\n'
         "            print('  {} (keyword-only)'.format(name))\n"
         '    elif param.kind == inspect.Parameter.VAR_KEYWORD:\n'
         "        print('  **{}'.format(name))",
 '_i17': 'import inspect\n'
         'import example\n'
         '\n'
         'sig = inspect.signature(example.module_level_function)\n'
         '\n'
         'bound = sig.bind(\n'
         "    'this is arg1',\n"
         "    'this is arg2',\n"
         "    'this is an extra positional argument',\n"
         "    extra_named_arg='value',\n"
         ')\n'
         '\n'
         "print('Arguments:')\n"
         'for name, value in bound.arguments.items():\n'
         "    print('{} = {!r}'.format(name, value))\n"
         '\n'
         "print('\\nCalling:')\n"
         'print(example.module_level_function(*bound.args, **bound.kwargs))',
 '_i18': 'import inspect\n'
         'import example\n'
         '\n'
         '\n'
         'class C(example.B):\n'
         '    pass\n'
         '\n'
         '\n'
         'class D(C, example.A):\n'
         '    pass\n'
         '\n'
         '\n'
         'def print_class_tree(tree, indent=-1):\n'
         '    if isinstance(tree, list):\n'
         '        for node in tree:\n'
         '            print_class_tree(node, indent + 1)\n'
         '    else:\n'
         "        print('  ' * indent, tree[0].__name__)\n"
         '    return\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         "    print('A, B, C, D:')\n"
         '    print_class_tree(inspect.getclasstree(\n'
         '        [example.A, example.B, C, D])\n'
         '    )',
 '_i19': 'import inspect\n'
         'import example\n'
         'from inspect_getclasstree import *\n'
         '\n'
         'print_class_tree(inspect.getclasstree(\n'
         '    [example.A, example.B, C, D],\n'
         '    unique=True,\n'
         '))',
 '_i2': '%load example.py',
 '_i20': 'import inspect\n'
         'import example\n'
         '\n'
         'print_class_tree(inspect.getclasstree(\n'
         '    [example.A, example.B, C, D],\n'
         '    unique=True,\n'
         '))',
 '_i21': 'import inspect\n'
         'import example\n'
         '\n'
         '\n'
         'class C(object):\n'
         '    pass\n'
         '\n'
         '\n'
         'class C_First(C, example.B):\n'
         '    pass\n'
         '\n'
         '\n'
         'class B_First(example.B, C):\n'
         '    pass\n'
         '\n'
         '\n'
         "print('B_First:')\n"
         'for c in inspect.getmro(B_First):\n'
         "    print('  {}'.format(c.__name__))\n"
         'print()\n'
         "print('C_First:')\n"
         'for c in inspect.getmro(C_First):\n'
         "    print('  {}'.format(c.__name__))",
 '_i22': '\n'
         'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         "def recurse(limit, keyword='default', *, kwonly='must be named'):\n"
         "    local_variable = '.' * limit\n"
         "    keyword = 'changed value of argument'\n"
         '    frame = inspect.currentframe()\n'
         "    print('line {} of {}'.format(frame.f_lineno,\n"
         '                                 frame.f_code.co_filename))\n'
         "    print('locals:')\n"
         '    pprint.pprint(frame.f_locals)\n'
         '    print()\n'
         '    if limit <= 0:\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)',
 '_i23': 'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         'def show_stack():\n'
         '    for level in inspect.stack():\n'
         "        print('{}[{}]\\n  -> {}'.format(\n"
         '            level.frame.f_code.co_filename,\n'
         '            level.lineno,\n'
         '            level.code_context[level.index].strip(),\n'
         '        ))\n'
         '        pprint.pprint(level.frame.f_locals)\n'
         '        print()\n'
         '\n'
         '\n'
         'def recurse(limit):\n'
         "    local_variable = '.' * limit\n"
         '    if limit <= 0:\n'
         '        show_stack()\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)',
 '_i3': 'import inspect\n'
        '\n'
        'import example\n'
        '\n'
        'for name, data in inspect.getmembers(example):\n'
        "    if name.startswith('__'):\n"
        '        continue\n'
        "    print('{} : {!r}'.format(name, data))",
 '_i4': 'import inspect\n'
        '\n'
        'import example\n'
        '\n'
        'for name, data in inspect.getmembers(example, inspect.isclass):\n'
        "    print('{} : {!r}'.format(name, data))",
 '_i5': 'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        'pprint(inspect.getmembers(example.A), width=65)',
 '_i6': 'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        'pprint(inspect.getmembers(example.A, inspect.isfunction))',
 '_i7': 'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        'pprint(inspect.getmembers(example.B, inspect.isfunction))',
 '_i8': 'import inspect\n'
        'from pprint import pprint\n'
        '\n'
        'import example\n'
        '\n'
        "a = example.A(name='inspect_getmembers')\n"
        'pprint(inspect.getmembers(a, inspect.ismethod))',
 '_i9': 'The docstring for an object can be retrieved with getdoc(). The '
        'return value is the __doc__ attribute with tabs expanded to spaces '
        'and with indentation made uniform.',
 '_ih': ['',
         '\n'
         "def module_level_function(arg1, arg2='default', *args, **kwargs):\n"
         '    """This function is declared in the module."""\n'
         '    local_variable = arg1 * 2\n'
         '    return local_variable\n'
         '\n'
         '\n'
         'class A(object):\n'
         '    """The A class."""\n'
         '\n'
         '    def __init__(self, name):\n'
         '        self.name = name\n'
         '\n'
         '    def get_name(self):\n'
         '        "Returns the name of the instance."\n'
         '        return self.name\n'
         '\n'
         '\n'
         "instance_of_a = A('sample_instance')\n"
         '\n'
         '\n'
         'class B(A):\n'
         '    """This is the B class.\n'
         '    It is derived from A.\n'
         '    """\n'
         '\n'
         '    # This method is not part of A.\n'
         '    def do_something(self):\n'
         '        """Does some work"""\n'
         '\n'
         '    def get_name(self):\n'
         '        "Overrides version from A"\n'
         "        return 'B(' + self.name + ')'",
         "get_ipython().magic('load example.py')",
         'import inspect\n'
         '\n'
         'import example\n'
         '\n'
         'for name, data in inspect.getmembers(example):\n'
         "    if name.startswith('__'):\n"
         '        continue\n'
         "    print('{} : {!r}'.format(name, data))",
         'import inspect\n'
         '\n'
         'import example\n'
         '\n'
         'for name, data in inspect.getmembers(example, inspect.isclass):\n'
         "    print('{} : {!r}'.format(name, data))",
         'import inspect\n'
         'from pprint import pprint\n'
         '\n'
         'import example\n'
         '\n'
         'pprint(inspect.getmembers(example.A), width=65)',
         'import inspect\n'
         'from pprint import pprint\n'
         '\n'
         'import example\n'
         '\n'
         'pprint(inspect.getmembers(example.A, inspect.isfunction))',
         'import inspect\n'
         'from pprint import pprint\n'
         '\n'
         'import example\n'
         '\n'
         'pprint(inspect.getmembers(example.B, inspect.isfunction))',
         'import inspect\n'
         'from pprint import pprint\n'
         '\n'
         'import example\n'
         '\n'
         "a = example.A(name='inspect_getmembers')\n"
         'pprint(inspect.getmembers(a, inspect.ismethod))',
         'The docstring for an object can be retrieved with getdoc(). The '
         'return value is the __doc__ attribute with tabs expanded to spaces '
         'and with indentation made uniform.',
         'import inspect\n'
         'import example\n'
         '\n'
         "print('B.__doc__:')\n"
         'print(example.B.__doc__)\n'
         'print()\n'
         "print('getdoc(B):')\n"
         'print(inspect.getdoc(example.B))',
         'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getcomments(example.B.do_something))',
         'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getcomments(example))',
         'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getsource(example.A))',
         'import inspect\n'
         'import example\n'
         '\n'
         'print(inspect.getsource(example.A.get_name))',
         'import inspect\n'
         'import pprint\n'
         'import example\n'
         '\n'
         'pprint.pprint(inspect.getsourcelines(example.A.get_name))',
         'import inspect\n'
         'import example\n'
         '\n'
         'sig = inspect.signature(example.module_level_function)\n'
         "print('module_level_function{}'.format(sig))\n"
         '\n'
         "print('\\nParameter details:')\n"
         'for name, param in sig.parameters.items():\n'
         '    if param.kind == inspect.Parameter.POSITIONAL_ONLY:\n'
         "        print('  {} (positional-only)'.format(name))\n"
         '    elif param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD:\n'
         '        if param.default != inspect.Parameter.empty:\n'
         "            print('  {}={!r}'.format(name, param.default))\n"
         '        else:\n'
         "            print('  {}'.format(name))\n"
         '    elif param.kind == inspect.Parameter.VAR_POSITIONAL:\n'
         "        print('  *{}'.format(name))\n"
         '    elif param.kind == inspect.Parameter.KEYWORD_ONLY:\n'
         '        if param.default != inspect.Parameter.empty:\n'
         "            print('  {}={!r} (keyword-only)'.format(\n"
         '                name, param.default))\n'
         '        else:\n'
         "            print('  {} (keyword-only)'.format(name))\n"
         '    elif param.kind == inspect.Parameter.VAR_KEYWORD:\n'
         "        print('  **{}'.format(name))",
         'import inspect\n'
         'import example\n'
         '\n'
         'sig = inspect.signature(example.module_level_function)\n'
         '\n'
         'bound = sig.bind(\n'
         "    'this is arg1',\n"
         "    'this is arg2',\n"
         "    'this is an extra positional argument',\n"
         "    extra_named_arg='value',\n"
         ')\n'
         '\n'
         "print('Arguments:')\n"
         'for name, value in bound.arguments.items():\n'
         "    print('{} = {!r}'.format(name, value))\n"
         '\n'
         "print('\\nCalling:')\n"
         'print(example.module_level_function(*bound.args, **bound.kwargs))',
         'import inspect\n'
         'import example\n'
         '\n'
         '\n'
         'class C(example.B):\n'
         '    pass\n'
         '\n'
         '\n'
         'class D(C, example.A):\n'
         '    pass\n'
         '\n'
         '\n'
         'def print_class_tree(tree, indent=-1):\n'
         '    if isinstance(tree, list):\n'
         '        for node in tree:\n'
         '            print_class_tree(node, indent + 1)\n'
         '    else:\n'
         "        print('  ' * indent, tree[0].__name__)\n"
         '    return\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         "    print('A, B, C, D:')\n"
         '    print_class_tree(inspect.getclasstree(\n'
         '        [example.A, example.B, C, D])\n'
         '    )',
         'import inspect\n'
         'import example\n'
         'from inspect_getclasstree import *\n'
         '\n'
         'print_class_tree(inspect.getclasstree(\n'
         '    [example.A, example.B, C, D],\n'
         '    unique=True,\n'
         '))',
         'import inspect\n'
         'import example\n'
         '\n'
         'print_class_tree(inspect.getclasstree(\n'
         '    [example.A, example.B, C, D],\n'
         '    unique=True,\n'
         '))',
         'import inspect\n'
         'import example\n'
         '\n'
         '\n'
         'class C(object):\n'
         '    pass\n'
         '\n'
         '\n'
         'class C_First(C, example.B):\n'
         '    pass\n'
         '\n'
         '\n'
         'class B_First(example.B, C):\n'
         '    pass\n'
         '\n'
         '\n'
         "print('B_First:')\n"
         'for c in inspect.getmro(B_First):\n'
         "    print('  {}'.format(c.__name__))\n"
         'print()\n'
         "print('C_First:')\n"
         'for c in inspect.getmro(C_First):\n'
         "    print('  {}'.format(c.__name__))",
         '\n'
         'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         "def recurse(limit, keyword='default', *, kwonly='must be named'):\n"
         "    local_variable = '.' * limit\n"
         "    keyword = 'changed value of argument'\n"
         '    frame = inspect.currentframe()\n'
         "    print('line {} of {}'.format(frame.f_lineno,\n"
         '                                 frame.f_code.co_filename))\n'
         "    print('locals:')\n"
         '    pprint.pprint(frame.f_locals)\n'
         '    print()\n'
         '    if limit <= 0:\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)',
         'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         'def show_stack():\n'
         '    for level in inspect.stack():\n'
         "        print('{}[{}]\\n  -> {}'.format(\n"
         '            level.frame.f_code.co_filename,\n'
         '            level.lineno,\n'
         '            level.code_context[level.index].strip(),\n'
         '        ))\n'
         '        pprint.pprint(level.frame.f_locals)\n'
         '        print()\n'
         '\n'
         '\n'
         'def recurse(limit):\n'
         "    local_variable = '.' * limit\n"
         '    if limit <= 0:\n'
         '        show_stack()\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)'],
 '_ii': 'import inspect\n'
        'import example\n'
        '\n'
        '\n'
        'class C(object):\n'
        '    pass\n'
        '\n'
        '\n'
        'class C_First(C, example.B):\n'
        '    pass\n'
        '\n'
        '\n'
        'class B_First(example.B, C):\n'
        '    pass\n'
        '\n'
        '\n'
        "print('B_First:')\n"
        'for c in inspect.getmro(B_First):\n'
        "    print('  {}'.format(c.__name__))\n"
        'print()\n'
        "print('C_First:')\n"
        'for c in inspect.getmro(C_First):\n'
        "    print('  {}'.format(c.__name__))",
 '_iii': 'import inspect\n'
         'import example\n'
         '\n'
         'print_class_tree(inspect.getclasstree(\n'
         '    [example.A, example.B, C, D],\n'
         '    unique=True,\n'
         '))',
 '_oh': {},
 '_sh': <module 'IPython.core.shadowns' from '/home/scott/anaconda3/lib/python3.6/site-packages/IPython/core/shadowns.py'>,
 'a': <example.A object at 0x7f5dc06c9cf8>,
 'bound': <BoundArguments (arg1='this is arg1', arg2='this is arg2', args=('this is an extra positional argument',), kwargs={'extra_named_arg': 'value'})>,
 'c': <class 'object'>,
 'data': <class 'example.B'>,
 'example': <module 'example' from '/home/scott/github/Python-3-Module-of-the-Week/language_tool/example.py'>,
 'exit': <IPython.core.autocall.ZMQExitAutocall object at 0x7f5dc2fd7ef0>,
 'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f5dcb281e10>>,
 'inspect': <module 'inspect' from '/home/scott/anaconda3/lib/python3.6/inspect.py'>,
 'instance_of_a': <__main__.A object at 0x7f5dc06bfa20>,
 'module_level_function': <function module_level_function at 0x7f5dc07312f0>,
 'name': 'kwargs',
 'param': <Parameter "**kwargs">,
 'pprint': <module 'pprint' from '/home/scott/anaconda3/lib/python3.6/pprint.py'>,
 'print_class_tree': <function print_class_tree at 0x7f5dc0717f28>,
 'quit': <IPython.core.autocall.ZMQExitAutocall object at 0x7f5dc2fd7ef0>,
 'recurse': <function recurse at 0x7f5dc06430d0>,
 'show_stack': <function show_stack at 0x7f5dc0643048>,
 'sig': <Signature (arg1, arg2='default', *args, **kwargs)>,
 'value': {'extra_named_arg': 'value'}}

/home/scott/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py[2881]
  -> exec(code_obj, self.user_global_ns, self.user_ns)
{'code_obj': <code object <module> at 0x7f5dc0637540, file "<ipython-input-23-70367c7817ec>", line 25>,
 'old_excepthook': <bound method IPKernelApp.excepthook of <ipykernel.kernelapp.IPKernelApp object at 0x7f5dccefe7b8>>,
 'outflag': 1,
 'result': <ExecutionResult object at 7f5dc06e79e8, execution_count=23 error_before_exec=None error_in_exec=None result=None>,
 'self': <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f5dcb281e10>}

/home/scott/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py[2821]
  -> if self.run_code(code, result):
{'cell_name': '<ipython-input-23-70367c7817ec>',
 'code': <code object <module> at 0x7f5dc0637540, file "<ipython-input-23-70367c7817ec>", line 25>,
 'compiler': <IPython.core.compilerop.CachingCompiler object at 0x7f5dc2fd1fd0>,
 'i': 4,
 'interactivity': 'none',
 'mod': <_ast.Module object at 0x7f5dc064bc88>,
 'node': <_ast.If object at 0x7f5dc064b9e8>,
 'nodelist': [<_ast.Import object at 0x7f5dc06e76a0>,
              <_ast.Import object at 0x7f5dc06e7ef0>,
              <_ast.FunctionDef object at 0x7f5dc06e7da0>,
              <_ast.FunctionDef object at 0x7f5dc064b4a8>,
              <_ast.If object at 0x7f5dc064b9e8>],
 'result': <ExecutionResult object at 7f5dc06e79e8, execution_count=23 error_before_exec=None error_in_exec=None result=None>,
 'self': <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f5dcb281e10>,
 'to_run_exec': [<_ast.Import object at 0x7f5dc06e76a0>,
                 <_ast.Import object at 0x7f5dc06e7ef0>,
                 <_ast.FunctionDef object at 0x7f5dc06e7da0>,
                 <_ast.FunctionDef object at 0x7f5dc064b4a8>,
                 <_ast.If object at 0x7f5dc064b9e8>],
 'to_run_interactive': []}

/home/scott/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py[2717]
  -> interactivity=interactivity, compiler=compiler, result=result)
{'cell': 'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         'def show_stack():\n'
         '    for level in inspect.stack():\n'
         "        print('{}[{}]\\n  -> {}'.format(\n"
         '            level.frame.f_code.co_filename,\n'
         '            level.lineno,\n'
         '            level.code_context[level.index].strip(),\n'
         '        ))\n'
         '        pprint.pprint(level.frame.f_locals)\n'
         '        print()\n'
         '\n'
         '\n'
         'def recurse(limit):\n'
         "    local_variable = '.' * limit\n"
         '    if limit <= 0:\n'
         '        show_stack()\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)\n',
 'cell_name': '<ipython-input-23-70367c7817ec>',
 'code_ast': <_ast.Module object at 0x7f5dc06c9ac8>,
 'compiler': <IPython.core.compilerop.CachingCompiler object at 0x7f5dc2fd1fd0>,
 'error_before_exec': <function InteractiveShell.run_cell.<locals>.error_before_exec at 0x7f5dc0731158>,
 'interactivity': 'last_expr',
 'preprocessing_exc_tuple': None,
 'raw_cell': 'import inspect\n'
             'import pprint\n'
             '\n'
             '\n'
             'def show_stack():\n'
             '    for level in inspect.stack():\n'
             "        print('{}[{}]\\n  -> {}'.format(\n"
             '            level.frame.f_code.co_filename,\n'
             '            level.lineno,\n'
             '            level.code_context[level.index].strip(),\n'
             '        ))\n'
             '        pprint.pprint(level.frame.f_locals)\n'
             '        print()\n'
             '\n'
             '\n'
             'def recurse(limit):\n'
             "    local_variable = '.' * limit\n"
             '    if limit <= 0:\n'
             '        show_stack()\n'
             '        return\n'
             '    recurse(limit - 1)\n'
             '    return local_variable\n'
             '\n'
             '\n'
             "if __name__ == '__main__':\n"
             '    recurse(2)\n',
 'result': <ExecutionResult object at 7f5dc06e79e8, execution_count=23 error_before_exec=None error_in_exec=None result=None>,
 'self': <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f5dcb281e10>,
 'shell_futures': True,
 'silent': False,
 'store_history': True}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/zmqshell.py[533]
  -> return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)
{'__class__': <class 'ipykernel.zmqshell.ZMQInteractiveShell'>,
 'args': ('import inspect\n'
          'import pprint\n'
          '\n'
          '\n'
          'def show_stack():\n'
          '    for level in inspect.stack():\n'
          "        print('{}[{}]\\n  -> {}'.format(\n"
          '            level.frame.f_code.co_filename,\n'
          '            level.lineno,\n'
          '            level.code_context[level.index].strip(),\n'
          '        ))\n'
          '        pprint.pprint(level.frame.f_locals)\n'
          '        print()\n'
          '\n'
          '\n'
          'def recurse(limit):\n'
          "    local_variable = '.' * limit\n"
          '    if limit <= 0:\n'
          '        show_stack()\n'
          '        return\n'
          '    recurse(limit - 1)\n'
          '    return local_variable\n'
          '\n'
          '\n'
          "if __name__ == '__main__':\n"
          '    recurse(2)\n',),
 'kwargs': {'silent': False, 'store_history': True},
 'self': <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f5dcb281e10>}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/ipkernel.py[196]
  -> res = shell.run_cell(code, store_history=store_history, silent=silent)
{'allow_stdin': True,
 'code': 'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         'def show_stack():\n'
         '    for level in inspect.stack():\n'
         "        print('{}[{}]\\n  -> {}'.format(\n"
         '            level.frame.f_code.co_filename,\n'
         '            level.lineno,\n'
         '            level.code_context[level.index].strip(),\n'
         '        ))\n'
         '        pprint.pprint(level.frame.f_locals)\n'
         '        print()\n'
         '\n'
         '\n'
         'def recurse(limit):\n'
         "    local_variable = '.' * limit\n"
         '    if limit <= 0:\n'
         '        show_stack()\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)\n',
 'reply_content': {},
 'self': <ipykernel.ipkernel.IPythonKernel object at 0x7f5dc30118d0>,
 'shell': <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f5dcb281e10>,
 'silent': False,
 'store_history': True,
 'user_expressions': {}}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelbase.py[399]
  -> user_expressions, allow_stdin)
{'allow_stdin': True,
 'code': 'import inspect\n'
         'import pprint\n'
         '\n'
         '\n'
         'def show_stack():\n'
         '    for level in inspect.stack():\n'
         "        print('{}[{}]\\n  -> {}'.format(\n"
         '            level.frame.f_code.co_filename,\n'
         '            level.lineno,\n'
         '            level.code_context[level.index].strip(),\n'
         '        ))\n'
         '        pprint.pprint(level.frame.f_locals)\n'
         '        print()\n'
         '\n'
         '\n'
         'def recurse(limit):\n'
         "    local_variable = '.' * limit\n"
         '    if limit <= 0:\n'
         '        show_stack()\n'
         '        return\n'
         '    recurse(limit - 1)\n'
         '    return local_variable\n'
         '\n'
         '\n'
         "if __name__ == '__main__':\n"
         '    recurse(2)\n',
 'content': {'allow_stdin': True,
             'code': 'import inspect\n'
                     'import pprint\n'
                     '\n'
                     '\n'
                     'def show_stack():\n'
                     '    for level in inspect.stack():\n'
                     "        print('{}[{}]\\n  -> {}'.format(\n"
                     '            level.frame.f_code.co_filename,\n'
                     '            level.lineno,\n'
                     '            level.code_context[level.index].strip(),\n'
                     '        ))\n'
                     '        pprint.pprint(level.frame.f_locals)\n'
                     '        print()\n'
                     '\n'
                     '\n'
                     'def recurse(limit):\n'
                     "    local_variable = '.' * limit\n"
                     '    if limit <= 0:\n'
                     '        show_stack()\n'
                     '        return\n'
                     '    recurse(limit - 1)\n'
                     '    return local_variable\n'
                     '\n'
                     '\n'
                     "if __name__ == '__main__':\n"
                     '    recurse(2)\n',
             'silent': False,
             'stop_on_error': True,
             'store_history': True,
             'user_expressions': {}},
 'ident': [b'4742C3D8B7F8453FAD74C98250C0F897'],
 'metadata': {'dependencies_met': True,
              'engine': '108d5e78-ab7a-4803-bfa9-ae0dbdde3059',
              'started': datetime.datetime(2017, 10, 27, 8, 38, 4, 838820, tzinfo=datetime.timezone.utc)},
 'parent': {'buffers': [],
            'content': {'allow_stdin': True,
                        'code': 'import inspect\n'
                                'import pprint\n'
                                '\n'
                                '\n'
                                'def show_stack():\n'
                                '    for level in inspect.stack():\n'
                                "        print('{}[{}]\\n  -> {}'.format(\n"
                                '            level.frame.f_code.co_filename,\n'
                                '            level.lineno,\n'
                                '            '
                                'level.code_context[level.index].strip(),\n'
                                '        ))\n'
                                '        pprint.pprint(level.frame.f_locals)\n'
                                '        print()\n'
                                '\n'
                                '\n'
                                'def recurse(limit):\n'
                                "    local_variable = '.' * limit\n"
                                '    if limit <= 0:\n'
                                '        show_stack()\n'
                                '        return\n'
                                '    recurse(limit - 1)\n'
                                '    return local_variable\n'
                                '\n'
                                '\n'
                                "if __name__ == '__main__':\n"
                                '    recurse(2)\n',
                        'silent': False,
                        'stop_on_error': True,
                        'store_history': True,
                        'user_expressions': {}},
            'header': {'date': datetime.datetime(2017, 10, 27, 8, 38, 4, 836065, tzinfo=datetime.timezone.utc),
                       'msg_id': '826D78615AEB430095B2F7D226FB5CA4',
                       'msg_type': 'execute_request',
                       'session': '4742C3D8B7F8453FAD74C98250C0F897',
                       'username': 'username',
                       'version': '5.0'},
            'metadata': {},
            'msg_id': '826D78615AEB430095B2F7D226FB5CA4',
            'msg_type': 'execute_request',
            'parent_header': {}},
 'self': <ipykernel.ipkernel.IPythonKernel object at 0x7f5dc30118d0>,
 'silent': False,
 'stop_on_error': True,
 'store_history': True,
 'stream': <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>,
 'user_expressions': {}}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelbase.py[235]
  -> handler(stream, idents, msg)
{'handler': <bound method Kernel.execute_request of <ipykernel.ipkernel.IPythonKernel object at 0x7f5dc30118d0>>,
 'header': {'date': datetime.datetime(2017, 10, 27, 8, 38, 4, 836065, tzinfo=datetime.timezone.utc),
            'msg_id': '826D78615AEB430095B2F7D226FB5CA4',
            'msg_type': 'execute_request',
            'session': '4742C3D8B7F8453FAD74C98250C0F897',
            'username': 'username',
            'version': '5.0'},
 'idents': [b'4742C3D8B7F8453FAD74C98250C0F897'],
 'msg': {'buffers': [],
         'content': {'allow_stdin': True,
                     'code': 'import inspect\n'
                             'import pprint\n'
                             '\n'
                             '\n'
                             'def show_stack():\n'
                             '    for level in inspect.stack():\n'
                             "        print('{}[{}]\\n  -> {}'.format(\n"
                             '            level.frame.f_code.co_filename,\n'
                             '            level.lineno,\n'
                             '            '
                             'level.code_context[level.index].strip(),\n'
                             '        ))\n'
                             '        pprint.pprint(level.frame.f_locals)\n'
                             '        print()\n'
                             '\n'
                             '\n'
                             'def recurse(limit):\n'
                             "    local_variable = '.' * limit\n"
                             '    if limit <= 0:\n'
                             '        show_stack()\n'
                             '        return\n'
                             '    recurse(limit - 1)\n'
                             '    return local_variable\n'
                             '\n'
                             '\n'
                             "if __name__ == '__main__':\n"
                             '    recurse(2)\n',
                     'silent': False,
                     'stop_on_error': True,
                     'store_history': True,
                     'user_expressions': {}},
         'header': {'date': datetime.datetime(2017, 10, 27, 8, 38, 4, 836065, tzinfo=datetime.timezone.utc),
                    'msg_id': '826D78615AEB430095B2F7D226FB5CA4',
                    'msg_type': 'execute_request',
                    'session': '4742C3D8B7F8453FAD74C98250C0F897',
                    'username': 'username',
                    'version': '5.0'},
         'metadata': {},
         'msg_id': '826D78615AEB430095B2F7D226FB5CA4',
         'msg_type': 'execute_request',
         'parent_header': {}},
 'msg_id': '826D78615AEB430095B2F7D226FB5CA4',
 'msg_type': 'execute_request',
 'self': <ipykernel.ipkernel.IPythonKernel object at 0x7f5dc30118d0>,
 'stream': <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelbase.py[283]
  -> return self.dispatch_shell(stream, msg)
{'msg': [<zmq.sugar.frame.Frame object at 0x7f5dc079e8e8>,
         <zmq.sugar.frame.Frame object at 0x7f5dc079e9a0>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db048>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db100>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db1b8>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db270>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db328>],
 'self': <ipykernel.ipkernel.IPythonKernel object at 0x7f5dc30118d0>,
 'stream': <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>}

/home/scott/anaconda3/lib/python3.6/site-packages/tornado/stack_context.py[277]
  -> return fn(*args, **kwargs)
{'args': ([<zmq.sugar.frame.Frame object at 0x7f5dc079e8e8>,
           <zmq.sugar.frame.Frame object at 0x7f5dc079e9a0>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db048>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db100>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db1b8>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db270>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db328>],),
 'cap_contexts': [((), None)],
 'current_state': ((), None),
 'fn': <function Kernel.start.<locals>.make_dispatcher.<locals>.dispatcher at 0x7f5dc07172f0>,
 'kwargs': {}}

/home/scott/anaconda3/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py[414]
  -> callback(*args, **kwargs)
{'args': ([<zmq.sugar.frame.Frame object at 0x7f5dc079e8e8>,
           <zmq.sugar.frame.Frame object at 0x7f5dc079e9a0>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db048>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db100>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db1b8>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db270>,
           <zmq.sugar.frame.Frame object at 0x7f5dc06db328>],),
 'callback': <function wrap.<locals>.null_wrapper at 0x7f5dc0717378>,
 'kwargs': {},
 'self': <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>}

/home/scott/anaconda3/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py[472]
  -> self._run_callback(callback, msg)
{'callback': <function wrap.<locals>.null_wrapper at 0x7f5dc0717378>,
 'msg': [<zmq.sugar.frame.Frame object at 0x7f5dc079e8e8>,
         <zmq.sugar.frame.Frame object at 0x7f5dc079e9a0>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db048>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db100>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db1b8>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db270>,
         <zmq.sugar.frame.Frame object at 0x7f5dc06db328>],
 'self': <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>}

/home/scott/anaconda3/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py[440]
  -> self._handle_recv()
{'events': 1,
 'fd': <zmq.sugar.socket.Socket object at 0x7f5dc3022a68>,
 'self': <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>}

/home/scott/anaconda3/lib/python3.6/site-packages/tornado/stack_context.py[277]
  -> return fn(*args, **kwargs)
{'args': (<zmq.sugar.socket.Socket object at 0x7f5dc3022a68>, 1),
 'cap_contexts': [((), None)],
 'current_state': ((), None),
 'fn': <bound method ZMQStream._handle_events of <zmq.eventloop.zmqstream.ZMQStream object at 0x7f5dc30110f0>>,
 'kwargs': {}}

/home/scott/anaconda3/lib/python3.6/site-packages/tornado/ioloop.py[888]
  -> handler_func(fd_obj, events)
{'due_timeouts': None,
 'event_pairs': [(<zmq.sugar.socket.Socket object at 0x7f5dc3022a68>, 1)],
 'events': 1,
 'fd': <zmq.sugar.socket.Socket object at 0x7f5dc3022a68>,
 'fd_obj': <zmq.sugar.socket.Socket object at 0x7f5dc3022a68>,
 'handler_func': <function wrap.<locals>.null_wrapper at 0x7f5dc3006ea0>,
 'ncallbacks': 0,
 'old_current': <zmq.eventloop.ioloop.ZMQIOLoop object at 0x7f5dc30112b0>,
 'old_wakeup_fd': -1,
 'poll_timeout': 3600.0,
 'self': <zmq.eventloop.ioloop.ZMQIOLoop object at 0x7f5dc30110b8>,
 'timeout': None}

/home/scott/anaconda3/lib/python3.6/site-packages/zmq/eventloop/ioloop.py[177]
  -> super(ZMQIOLoop, self).start()
{'__class__': <class 'zmq.eventloop.ioloop.ZMQIOLoop'>,
 'self': <zmq.eventloop.ioloop.ZMQIOLoop object at 0x7f5dc30110b8>}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelapp.py[477]
  -> ioloop.IOLoop.instance().start()
{'self': <ipykernel.kernelapp.IPKernelApp object at 0x7f5dccefe7b8>}

/home/scott/anaconda3/lib/python3.6/site-packages/traitlets/config/application.py[658]
  -> app.start()
{'app': <ipykernel.kernelapp.IPKernelApp object at 0x7f5dccefe7b8>,
 'argv': None,
 'cls': <class 'ipykernel.kernelapp.IPKernelApp'>,
 'kwargs': {}}

/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py[16]
  -> app.launch_new_instance()
{'__annotations__': {},
 '__builtins__': <module 'builtins' (built-in)>,
 '__cached__': '/home/scott/anaconda3/lib/python3.6/site-packages/__pycache__/ipykernel_launcher.cpython-36.pyc',
 '__doc__': 'Entry point for launching an IPython kernel.\n'
            '\n'
            'This is separate from the ipykernel package so we can avoid doing '
            'imports until\n'
            'after removing the cwd from sys.path.\n',
 '__file__': '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py',
 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>,
 '__name__': '__main__',
 '__package__': '',
 '__spec__': ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>, origin='/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py'),
 'app': <module 'ipykernel.kernelapp' from '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelapp.py'>,
 'sys': <module 'sys' (built-in)>}

/home/scott/anaconda3/lib/python3.6/runpy.py[85]
  -> exec(code, run_globals)
{'cached': '/home/scott/anaconda3/lib/python3.6/site-packages/__pycache__/ipykernel_launcher.cpython-36.pyc',
 'code': <code object <module> at 0x7f5dcceb88a0, file "/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py", line 5>,
 'fname': '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py',
 'init_globals': None,
 'loader': <_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>,
 'mod_name': '__main__',
 'mod_spec': ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>, origin='/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py'),
 'pkg_name': '',
 'run_globals': {'__annotations__': {},
                 '__builtins__': <module 'builtins' (built-in)>,
                 '__cached__': '/home/scott/anaconda3/lib/python3.6/site-packages/__pycache__/ipykernel_launcher.cpython-36.pyc',
                 '__doc__': 'Entry point for launching an IPython kernel.\n'
                            '\n'
                            'This is separate from the ipykernel package so we '
                            'can avoid doing imports until\n'
                            'after removing the cwd from sys.path.\n',
                 '__file__': '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py',
                 '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>,
                 '__name__': '__main__',
                 '__package__': '',
                 '__spec__': ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>, origin='/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py'),
                 'app': <module 'ipykernel.kernelapp' from '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelapp.py'>,
                 'sys': <module 'sys' (built-in)>},
 'script_name': None}

/home/scott/anaconda3/lib/python3.6/runpy.py[193]
  -> "__main__", mod_spec)
{'alter_argv': 1,
 'code': <code object <module> at 0x7f5dcceb88a0, file "/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py", line 5>,
 'main_globals': {'__annotations__': {},
                  '__builtins__': <module 'builtins' (built-in)>,
                  '__cached__': '/home/scott/anaconda3/lib/python3.6/site-packages/__pycache__/ipykernel_launcher.cpython-36.pyc',
                  '__doc__': 'Entry point for launching an IPython kernel.\n'
                             '\n'
                             'This is separate from the ipykernel package so '
                             'we can avoid doing imports until\n'
                             'after removing the cwd from sys.path.\n',
                  '__file__': '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py',
                  '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>,
                  '__name__': '__main__',
                  '__package__': '',
                  '__spec__': ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>, origin='/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py'),
                  'app': <module 'ipykernel.kernelapp' from '/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel/kernelapp.py'>,
                  'sys': <module 'sys' (built-in)>},
 'mod_name': 'ipykernel_launcher',
 'mod_spec': ModuleSpec(name='ipykernel_launcher', loader=<_frozen_importlib_external.SourceFileLoader object at 0x7f5dcb281c88>, origin='/home/scott/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py')}

There are other functions for building lists of frames in different contexts, such as when an exception is being processed. See the documentation for trace(), getouterframes(), and getinnerframes() for more details.

Command Line Interface

The inspect module also includes a command line interface for getting details about objects without having to write out the calls in a separate Python program. The input is a module name and optional object from within the module. The default output is the source code for the named object. Using the --details argument causes metadata to be printed instead of the source.


In [24]:
!python3 -m inspect -d example


Target: example
Origin: /home/scott/github/Python-3-Module-of-the-Week/language_tool/example.py
Cached: /home/scott/github/Python-3-Module-of-the-Week/language_tool/__pycache__/example.cpython-36.pyc
Loader: <_frozen_importlib_external.SourceFileLoader object at 0x7fa8da62e438>



In [25]:
!python3 -m inspect -d example:A


Target: example:A
Origin: /home/scott/github/Python-3-Module-of-the-Week/language_tool/example.py
Cached: /home/scott/github/Python-3-Module-of-the-Week/language_tool/__pycache__/example.cpython-36.pyc
Line: 7



In [26]:
!python3 -m inspect example:A.get_name


    def get_name(self):
        "Returns the name of the instance."
        return self.name


In [ ]: