Home ยป Python Reflection Tutorial

Python Reflection Tutorial

Reflection in Python refers to the ability of a program to inspect and manipulate objects, classes, methods, and attributes at runtime.

Python’s dynamic nature makes reflection a powerful feature that can be used to introspect the program’s structure, modify behavior, or even dynamically invoke methods or access attributes.

In this tutorial, we will explore how to use reflection in Python with practical examples, including introspecting objects, checking and modifying attributes, invoking methods dynamically, and more.

1. Using the type() Function

The type() function is one of the simplest reflection tools in Python. It is used to determine the type (class) of an object.

Example: Checking the Type of an Object

# Example: Using type() to check the type of an object
x = 42
print(type(x))  # Output: <class 'int'>

y = "Hello"
print(type(y))  # Output: <class 'str'>

In this example:

type(x) returns the type of the variable x, which is an integer (int).
Similarly, type(y) returns the type of y, which is a string (str).

2. Using the isinstance() Function

The isinstance() function checks whether an object is an instance of a specific class or a tuple of classes.

Example: Checking if an Object is an Instance of a Class

# Example: Using isinstance() to check if an object is of a specific type
x = 42
print(isinstance(x, int))  # Output: True

y = "Hello"
print(isinstance(y, str))  # Output: True

# Check for multiple types
print(isinstance(x, (int, float)))  # Output: True

In this example:

isinstance(x, int) checks if x is an instance of the int class.
isinstance(y, str) checks if y is an instance of the str class.
You can also check for multiple types by passing a tuple of classes.

3. Using the dir() Function

The dir() function returns a list of all the attributes and methods of an object, including special attributes (those with double underscores, like __init__).

Example: Inspecting Attributes and Methods with dir()

# Example: Using dir() to inspect attributes and methods
class MyClass:
    def method1(self):
        pass

    def method2(self):
        pass

my_instance = MyClass()

# List all attributes and methods of the instance
print(dir(my_instance))

In this example:

dir(my_instance) lists all the attributes and methods of the MyClass instance, including its methods and built-in special methods like __init__, __class__, etc.

4. Using getattr() and setattr() Functions

The getattr() function is used to get the value of an object’s attribute dynamically. Similarly, setattr() allows you to set the value of an attribute dynamically.

Example: Getting and Setting Attributes Dynamically

# Example: Using getattr() and setattr()
class MyClass:
    def __init__(self):
        self.name = "Alice"
        self.age = 30

my_instance = MyClass()

# Get the value of an attribute dynamically
name = getattr(my_instance, 'name')
print(name)  # Output: Alice

# Set the value of an attribute dynamically
setattr(my_instance, 'age', 35)

# Verify the change
print(my_instance.age)  # Output: 35

In this example:

getattr(my_instance, ‘name’) gets the value of the name attribute.
setattr(my_instance, ‘age’, 35) sets the value of the age attribute to 35.

5. Using the hasattr() Function

The hasattr() function checks whether an object has a specified attribute.

Example: Checking if an Object Has an Attribute

# Example: Using hasattr() to check for an attribute
class MyClass:
    def __init__(self):
        self.name = "Alice"

my_instance = MyClass()

# Check if the object has the attribute 'name'
print(hasattr(my_instance, 'name'))  # Output: True

# Check if the object has a non-existent attribute 'age'
print(hasattr(my_instance, 'age'))  # Output: False

In this example:

hasattr(my_instance, ‘name’) checks if the name attribute exists.
hasattr(my_instance, ‘age’) returns False because the age attribute does not exist.

6. Invoking Methods Dynamically Using getattr()

Just like attributes, methods can also be dynamically invoked using the getattr() function.

Example: Dynamically Invoking Methods

# Example: Using getattr() to invoke methods dynamically
class MyClass:
    def greet(self):
        return "Hello, world!"

my_instance = MyClass()

# Get the method and invoke it
greet_method = getattr(my_instance, 'greet')
print(greet_method())  # Output: Hello, world!

In this example:

getattr(my_instance, ‘greet’) retrieves the greet() method and invokes it.

7. Using callable() to Check if an Object is Callable

The callable() function checks whether an object can be called like a function (e.g., methods or functions).

Example: Checking if an Object is Callable

# Example: Using callable() to check if an object is callable
def my_function():
    pass

class MyClass:
    def method(self):
        pass

my_instance = MyClass()

# Check if the function is callable
print(callable(my_function))  # Output: True

# Check if the method is callable
print(callable(my_instance.method))  # Output: True

# Check if an attribute is callable
print(callable(my_instance))  # Output: False

In this example:

callable(my_function) checks if my_function is callable.
callable(my_instance.method) checks if the method is callable.
callable(my_instance) returns False because my_instance is not callable.

8. Inspecting a Class’s Base Classes Using __bases__

You can inspect the base classes (superclasses) of a class using the __bases__ attribute.

Example: Inspecting a Class’s Base Classes

# Example: Inspecting base classes using __bases__
class Parent:
    pass

class Child(Parent):
    pass

# Get the base classes of Child
print(Child.__bases__)  # Output: (<class '__main__.Parent'>,)

In this example:

Child.__bases__ returns the tuple of base classes, showing that Child inherits from Parent.

9. Using the inspect Module

Python’s inspect module provides more advanced reflection features, such as getting detailed information about the arguments of a function or inspecting the source code of a function.

Example: Using inspect to Get Function Signature

# Example: Using inspect to get function signature
import inspect

def my_function(a, b, c=10):
    return a + b + c

# Get the function signature
signature = inspect.signature(my_function)
print(signature)  # Output: (a, b, c=10)

In this example:

inspect.signature(my_function) returns the signature of the my_function, showing the arguments and their default values.

Example: Using inspect to Get Source Code

# Example: Using inspect to get source code
import inspect

def my_function():
    print("Hello")

# Get the source code of the function
source_code = inspect.getsource(my_function)
print(source_code)

In this example:

inspect.getsource(my_function) returns the source code of the my_function.

10. Modifying Class Attributes Dynamically

You can dynamically modify the class itself by adding or modifying attributes or methods.

Example: Adding a New Method Dynamically

# Example: Adding a new method to a class dynamically
class MyClass:
    def __init__(self):
        self.name = "Alice"

def new_method(self):
    return "This is a dynamically added method"

# Add the method to the class dynamically
MyClass.new_method = new_method

my_instance = MyClass()

# Call the dynamically added method
print(my_instance.new_method())  # Output: This is a dynamically added method

In this example:

MyClass.new_method = new_method adds a new method to the MyClass dynamically. This method is then available to all instances of MyClass.

Summary

Reflection in Python allows you to inspect and manipulate objects, classes, and methods at runtime.
You can use type() to check the type of an object, isinstance() to check if an object is an instance of a class, and dir() to list all attributes and methods of an object.
getattr() and setattr() allow you to dynamically access and modify attributes, while hasattr() checks if an object has a specific attribute.
Methods can be dynamically invoked using getattr(), and callable() checks if an object is callable.
The inspect module provides advanced features for inspecting functions, including their signatures and source code.
Reflection can also be used to dynamically modify classes by adding attributes or methods.

By mastering these reflection techniques, you can write dynamic and flexible Python programs that can inspect and modify themselves at runtime.

You may also like

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More