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:
- type() Function
- isinstance() Function
- issubclass() Function
- callable() Function
- getattr() Function
- setattr() Function
- hasattr() Function
- dir() Function
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']