Python Reflection: Understanding Introspection and Object Information

Explore reflection in Python, also known as introspection, which lets you examine and extract information about objects. Learn how to determine object types, attributes, and subclass relationships using Python's standard library functions for reflection.



Python - Reflection

In object-oriented programming, reflection allows extracting information about an object. You can determine the type of object, its attributes, whether it is a subclass, and more. Reflection is also called introspection. Python's standard library has several reflection functions:

The type() Function

This function tells you the class an object belongs to.


print(type(10))
print(type(2.56))
print(type(2+3j))
print(type("Hello World"))
print(type([1, 2, 3]))
print(type({1: 'one', 2: 'two'}))
        
Output







        

To verify the type of an object of a user-defined class:


class test:
   pass

obj = test()
print(type(obj))
        
Output


        

The isinstance() Function

This function checks if an object is an instance of a given class. It returns a Boolean value.


print(isinstance(10, int))
print(isinstance(2.56, float))
print(isinstance(2+3j, complex))
print(isinstance("Hello World", str))
        
Output

True
True
True
True
        

Checking with a user-defined class:


class test:
   pass

obj = test()
print(isinstance(obj, test))
        
Output

True
        

All classes are objects of the object class:


class test:
   pass

print(isinstance(int, object))
print(isinstance(str, object))
print(isinstance(test, object))
        
Output

True
True
True
        

The issubclass() Function

This function checks if a class is a subclass of another class. It pertains to classes, not their instances.


class test:
   pass

print(issubclass(int, object))
print(issubclass(str, object))
print(issubclass(test, object))
        
Output

True
True
True
        

The callable() Function

This function checks if an object is callable. Functions, built-in, user-defined, or methods, are callable. Objects of built-in data types are not callable.


def test():
   pass

print(callable("Hello"))
print(callable(abs))
print(callable(list.clear([1, 2])))
print(callable(test))
        
Output

False
True
True
False
        

A class instance is callable if it has a __call__() method:


class test:
   def __init__(self):
      pass
   def __call__(self):
      print("Hello")

obj = test()
obj()
print("obj is callable?", callable(obj))
        
Output

Hello
obj is callable? True
        

The getattr() Function

This function retrieves the value of the named attribute of an object:


class test:
   def __init__(self):
      self.name = "Manav"

obj = test()
print(getattr(obj, "name"))
        
Output

Manav
        

The setattr() Function

This function adds a new attribute to an object and assigns it a value. It can also change the value of an existing attribute:


class test:
   def __init__(self):
      self.name = "Manav"

obj = test()
setattr(obj, "age", 20)
setattr(obj, "name", "Madhav")
print(obj.name, obj.age)
        
Output

Madhav 20
        

The hasattr() Function

This function returns True if the given attribute is available to the object argument and false if not:


class test:
   def __init__(self):
      self.name = "Manav"

obj = test()
print(hasattr(obj, "age"))
print(hasattr(obj, "name"))
        
Output

False
True
        

The dir() Function

This function returns the names in the current scope or attributes of the given object:


print("dir(int):", dir(int))
        
Output

dir(int): ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__getstate__', '__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']
        

print("dir(dict):", dir(dict))
        
Output

dir(dict): ['__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__ior__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
        

class test:
   def __init__(self):
      self.name = "Manav"

obj = test()
print("dir(obj):", dir(obj))
        
Output

dir(obj): ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']