Fundamentals 8 min read

Dynamic Class Creation and Modification in Python: 10 Practical Scenarios

This article explains Python's dynamic class creation and modification techniques—including the type function, metaclasses, and class decorators—through ten practical code examples that demonstrate how to build flexible, maintainable, and powerful object‑oriented designs.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
Dynamic Class Creation and Modification in Python: 10 Practical Scenarios

Dynamic class creation and modification are key metaprogramming techniques in Python that let developers define and alter class structures at runtime using the type function, metaclasses, and class decorators.

1. Using the type function to create a class dynamically:

MyClass = type("MyClass", (object,), {"x": 42})
obj = MyClass()
print(obj.x)  # 输出: 42

2. Using a metaclass to inject attributes into a class:

class MyMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs["y"] = 100
        return super().__new__(cls, name, bases, attrs)

class MyClass(metaclass=MyMeta):
    pass

obj = MyClass()
print(obj.y)  # 输出: 100

3. Using a class decorator to add attributes:

def my_decorator(cls):
    cls.z = 200
    return cls

@my_decorator
class MyClass:
    pass

obj = MyClass()
print(obj.z)  # 输出: 200

4. Implementing the Singleton pattern with a metaclass:

class SingletonMeta(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class SingletonClass(metaclass=SingletonMeta):
    pass

obj1 = SingletonClass()
obj2 = SingletonClass()
print(obj1 is obj2)  # 输出: True

5. Using a class decorator for attribute validation:

def validate_attributes(cls):
    original_init = cls.__init__
    def new_init(self, *args, **kwargs):
        for name, value in kwargs.items():
            if not isinstance(value, int):
                raise ValueError(f"Invalid value for attribute '{name}'")
        original_init(self, *args, **kwargs)
    cls.__init__ = new_init
    return cls

@validate_attributes
class MyClass:
    def __init__(self, x, y):
        self.x = x
        self.y = y

obj = MyClass(x=10, y=20)
print(obj.x, obj.y)  # 输出: 10 20
obj2 = MyClass(x=10, y="invalid")  # 抛出 ValueError

6. Implementing a method timer with a metaclass:

import time

class TimerMeta(type):
    def __new__(cls, name, bases, attrs):
        for attr, value in attrs.items():
            if callable(value):
                attrs[attr] = cls.wrap_method(value)
        return super().__new__(cls, name, bases, attrs)
    @staticmethod
    def wrap_method(method):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            result = method(*args, **kwargs)
            end_time = time.time()
            print(f"Method '{method.__name__}' executed in {end_time - start_time} seconds")
            return result
        return wrapper

class MyClass(metaclass=TimerMeta):
    def my_method(self):
        time.sleep(1)

obj = MyClass()
obj.my_method()  # 输出: Method 'my_method' executed in ... seconds

7. Adding caching to a method via a class decorator:

def cache_result(cls):
    cache = {}
    original_method = cls.method
    def new_method(self, *args):
        if args in cache:
            return cache[args]
        result = original_method(self, *args)
        cache[args] = result
        return result
    cls.method = new_method
    return cls

@cache_result
class MyClass:
    def method(self, x):
        print(f"Calculating result for {x}")
        return x * 2

obj = MyClass()
print(obj.method(5))  # 输出: Calculating result for 5, 10
print(obj.method(5))  # 输出: 10 (从缓存中获取)

8. Controlling attribute access with a metaclass:

class AccessControlMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs["_private_attr"] = 42
        return super().__new__(cls, name, bases, attrs)
    def __getattr__(cls, name):
        if name == "public_attr":
            return cls._private_attr
        raise AttributeError(f"Attribute '{name}' not found")

class MyClass(metaclass=AccessControlMeta):
    pass

obj = MyClass()
print(obj.public_attr)  # 输出: 42
print(obj._private_attr)  # 抛出 AttributeError

9. Logging method calls with a class decorator:

def log_calls(cls):
    original_method = cls.method
    def new_method(self, *args, **kwargs):
        print(f"Calling method '{method.__name__}' with args={args}, kwargs={kwargs}")
        return original_method(self, *args, **kwargs)
    cls.method = new_method
    return cls

@log_calls
class MyClass:
    def method(self, x):
        return x * 2

obj = MyClass()
obj.method(5)  # 输出: Calling method 'method' with args=(5,), kwargs={}

10. Enforcing interface contracts with a metaclass:

class InterfaceMeta(type):
    def __new__(cls, name, bases, attrs):
        if "__abstractmethods__" not in attrs:
            abstract_methods = set()
            for base in bases:
                if hasattr(base, "__abstractmethods__"):
                    abstract_methods.update(base.__abstractmethods__)
            for attr, value in attrs.items():
                if callable(value) and getattr(value, "__isabstractmethod__", False):
                    abstract_methods.add(attr)
            attrs["__abstractmethods__"] = frozenset(abstract_methods)
        return super().__new__(cls, name, bases, attrs)

class MyInterface(metaclass=InterfaceMeta):
    def method(self):
        raise NotImplementedError

class MyClass(MyInterface):
    pass
# 抛出 TypeError: Can't instantiate abstract class MyClass with abstract methods method

These ten examples demonstrate how Python's metaprogramming facilities can be leveraged to create, modify, and extend classes dynamically, resulting in more flexible and maintainable code.

PythonMetaprogrammingProgrammingDecoratorsMetaclassesDynamic Classes
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.