Introspection

Introspection

ℹ️

  • Checking id of object: id()

    • Check that objects have same id: is

  • Checking the type of object/variable:

    • type() - returns a type of object

    • isinstance(x, typeA) - returns True/False depends if object x of type typeA

  • dir() - return a list of valid attributes for argument (or list of names in current local scope if no argument)

  • sys.getsizeof() - get the size (in bytes) of the memory allocated byt the object

  • module inspect - low-level API for contents of a class, source code of a method, argument list for a function, detailed traceback

  • module dis - decompiling Python byte-code showing code execution trace

  • 3rd-party module rich has handly inspect method for inspecting any kind of Python object

Example of introspection of int object:

🪄 Code:

a = 42
print(dir(a))

📟 Output:

['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_count', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

We see a lot of methods available in object which gives us a hint what is the kind of object it is and what we can do with it.

Introspection of an instance of some class:

🪄 Code:

class A(object):      # Creating simple class
    attr1 = 5         # with one attribute: "attr1"
some_obj = A()
print(some_obj.attr1) # Checking the value of custom attribute
print(dir(some_obj))  # This will show all inherited methods and attribute we created: "attr1"

📟 Output:

5
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'attr1']

In this case we can see many inherited methods (from parent class called "object") and also attributes and methods defined by us (in this example it is just one attribute "attr1")

Getting the size of an object

sys.getsizeof() - get the size (in bytes) of the memory allocated byt the object.

🪄 Code:

import sys

sys.getsizeof(100500)

📟 Output:

28

## Introspection with `rich`

🔥

There is a nice library rich used for displaying various content to terminal. It is can be used as additional inspection tool in Python (or ipython/Jupyter also):

from rich import inspect

i = 100500

inspect(i)
╭────── <class 'int'> ───────╮
│ int([x]) -> integer        │
│ int(x, base=10) -> integer │
│                            │
│ ╭────────────────────────╮ │
│ │ 100500                 │ │
│ ╰────────────────────────╯ │
│                            │
│ denominator = 1            │
│        imag = 0            │
│   numerator = 100500       │
│        real = 100500       │
╰────────────────────────────╯

🔥

And with methods overview:

inspect(i, methods=True)
╭───────────────────────────────────────────────── <class 'int'> ─────────────────────────────────────────────────╮
│ int([x]) -> integer                                                                                             │
│ int(x, base=10) -> integer                                                                                      │
│                                                                                                                 │
│ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ 100500                                                                                                      │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                                 │
│      denominator = 1                                                                                            │
│             imag = 0                                                                                            │
│        numerator = 100500                                                                                       │
│             real = 100500                                                                                       │
│ as_integer_ratio = def as_integer_ratio(): Return integer ratio.                                                │
│        bit_count = def bit_count(): Number of ones in the binary representation of the absolute value of self.  │
│       bit_length = def bit_length(): Number of bits necessary to represent self in binary.                      │
│        conjugate = def conjugate(...) Returns self, the complex conjugate of any int.                           │
│       from_bytes = def from_bytes(bytes, byteorder, *, signed=False): Return the integer represented by the     │
│                    given array of bytes.                                                                        │
│         to_bytes = def to_bytes(length, byteorder, *, signed=False): Return an array of bytes representing an   │
│                    integer.                                                                                     │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

🔥

An example of list inspection:

inspect([1, 2, 3], methods=True)
╭───────────────────────────────────────── <class 'list'> ──────────────────────────────────────────╮
│ Built-in mutable sequence.                                                                        │
│                                                                                                   │
│ ╭───────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ [1, 2, 3]                                                                                     │ │
│ ╰───────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                   │
│  append = def append(object, /): Append object to the end of the list.                            │
│   clear = def clear(): Remove all items from list.                                                │
│    copy = def copy(): Return a shallow copy of the list.                                          │
│   count = def count(value, /): Return number of occurrences of value.                             │
│  extend = def extend(iterable, /): Extend list by appending elements from the iterable.           │
│   index = def index(value, start=0, stop=9223372036854775807, /): Return first index of value.    │
│  insert = def insert(index, object, /): Insert object before index.                               │
│     pop = def pop(index=-1, /): Remove and return item at index (default last).                   │
│  remove = def remove(value, /): Remove first occurrence of value.                                 │
│ reverse = def reverse(): Reverse *IN PLACE*.                                                      │
│    sort = def sort(*, key=None, reverse=False): Sort the list in ascending order and return None. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯

Basic types of objects in Python

CategoryExplanationTypes

Mutable

Object can be changed after creation

list, dict, set, bytearray

Immutable

Object can not be changed after creation

int, float, complex, str, tuple, frozenset

Sequence (collection, iterable)

Object can holds other object in itself (has magic methods like __getitem__())

list, tuple, set, str, frozenset, dict

Ordered

Members are ordered

list, str, tuple, dict

Unordered

Members are unordered

set, frozenset

Additional categories:

CategoryExplanationTypes

Hashable

Object that can be a key to dictionary (has __hash__() - all immutable and instances of custom classes)

tuple, int, float, str, frozenset, object

Iterable

Object capable of returning it's member one at a time (has __iter__() or __getitem__())

str, list, tuple, set, frozenset, dict

Callable

Object that can behave as function (has __call__() method defined)

class, function, method

Last updated