Fundamentals 6 min read

Python Reflection and Metaprogramming: Concepts and Practical Examples

This article explains Python's reflection and metaprogramming features, demonstrating how to inspect objects, dynamically invoke methods, create classes, use metaclasses, decorators, exec, inspect signatures, and other advanced techniques through ten clear code examples.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Python Reflection and Metaprogramming: Concepts and Practical Examples

Python's reflection and metaprogramming capabilities allow developers to inspect and manipulate program structures such as classes, methods, and variables at runtime, enabling dynamic behavior, code generation, framework construction, and automated testing.

Example 1: Retrieve an object's attributes and methods

def inspect_object(obj):
    print(f"Attributes of {obj}:")
    for attr in dir(obj):
        if not attr.startswith("__"):
            print(f"  - {attr}")

inspect_object(str)

Example 2: Dynamically call a method

class MyClass:
    def greet(self, message):
        print(message)

my_instance = MyClass()
method_name = "greet"
getattr(my_instance, method_name)("Hello, World!")

Example 3: Dynamically create a class

class_dict = {
    'say_hello': (lambda self: print("Hello from DynamicClass"))
}
DynamicClass = type('DynamicClass', (), class_dict)
instance = DynamicClass()
instance.say_hello()

Example 4: Use a metaclass to customize class creation

class Meta(type):
    def __new__(cls, name, bases, attrs):
        attrs['class_name'] = name
        return super().__new__(cls, name, bases, attrs)

class MyClass(metaclass=Meta):
    pass

print(MyClass.class_name)

Example 5: Modify a class definition with a decorator

def add_attribute(attr_name, attr_value):
    def decorator(cls):
        setattr(cls, attr_name, attr_value)
        return cls
    return decorator

@add_attribute('my_attr', 'My Value')
class MyClass:
    pass

print(MyClass.my_attr)

Example 6: Use __metaclass__ (Python 2 style)

__metaclass__ = type

class MyClass:
    def __init__(self):
        self.class_name = self.__class__.__name__

print(MyClass().class_name)
# Note: In Python 3, __metaclass__ is deprecated; use the metaclass keyword instead.

Example 7: Execute code strings dynamically with exec()

code = """
class MyClass:
    def say_hello(self):
        print("Hello from MyClass")
"""
exec(code)
my_instance = MyClass()
my_instance.say_hello()

Example 8: Retrieve a function's signature using the inspect module

import inspect

def example_function(a, b, c=1):
    pass

signature = inspect.signature(example_function)
print(signature)

Example 9: Preserve decorator metadata with functools.wraps

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print("Before function call")
        result = func(*args, **kwargs)
        print("After function call")
        return result
    return wrapper

@my_decorator
def say_hello(name):
    """Says hello to the given name."""
    print(f"Hello, {name}!")

print(say_hello.__name__)
print(say_hello.__doc__)

Example 10: Obtain module information with the sys module

import sys
module_info = sys.modules[__name__]
print(f"Module Name: {module_info.__name__}")
print(f"Module Docstring: {module_info.__doc__}")

The above examples illustrate common uses of Python reflection and metaprogramming; while powerful, they should be applied judiciously because they can make code harder to understand and debug. When used appropriately, these techniques greatly enhance flexibility and extensibility.

If you want to enrich your Python projects or dive deeper into the language's underlying mechanisms, exploring reflection and metaprogramming is highly worthwhile. Follow our WeChat subscription for more advanced Python topics.

Should you encounter any issues while trying the examples or wish to explore more complex metaprogramming scenarios, feel free to ask for help—I’m here to provide guidance.

Remember to balance the use of reflection and metaprogramming with code readability and maintainability; overuse may introduce unnecessary complexity. Reach out anytime if you have questions about striking that balance.

PythonmetaprogrammingreflectionDynamicintrospection
Test Development Learning Exchange
Written by

Test Development Learning Exchange

Test Development Learning Exchange

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.