Fundamentals 6 min read

10 Practical Python Metaprogramming Scenarios Using __getattr__, __setattr__, Property Decorators, Descriptors, and Metaclasses

This article demonstrates ten practical Python metaprogramming techniques—including dynamic attribute access with __getattr__, attribute assignment with __setattr__, descriptor-based validation, property decorators, dynamic class and method creation, and metaclass usage—providing complete code examples for each scenario.

Test Development Learning Exchange
Test Development Learning Exchange
Test Development Learning Exchange
10 Practical Python Metaprogramming Scenarios Using __getattr__, __setattr__, Property Decorators, Descriptors, and Metaclasses

Metaprogramming in Python enables creating, modifying, or manipulating program structure and behavior at runtime. The article presents ten practical scenarios that illustrate how to use __getattr__ , __setattr__ , descriptors, property decorators, dynamic class creation, dynamic method creation, and metaclasses.

1. Using __getattr__ to retrieve dynamic attributes:

class DynamicAttributes:
    def __getattr__(self, name):
        if name == "dynamic_attribute":
            return "This is a dynamic attribute"
        else:
            raise AttributeError(f"{name} is not found")

obj = DynamicAttributes()
print(obj.dynamic_attribute)  # This is a dynamic attribute
print(obj.undefined_attribute)  # raises AttributeError

2. Using __setattr__ to set dynamic attributes and log assignments:

class DynamicAttributes:
    def __setattr__(self, name, value):
        print(f"Setting {name} to {value}")
        super().__setattr__(name, value)

obj = DynamicAttributes()
obj.dynamic_attribute = 10  # Output: Setting dynamic_attribute to 10

3. Implementing attribute access control with a descriptor:

class PositiveNumber:
    def __get__(self, instance, owner):
        return instance.__dict__[self.name]
    def __set__(self, instance, value):
        if value <= 0:
            raise ValueError("Value must be positive")
        instance.__dict__[self.name] = value
    def __set_name__(self, owner, name):
        self.name = name

class MyClass:
    positive_number = PositiveNumber()

obj = MyClass()
obj.positive_number = 10
print(obj.positive_number)  # 10
obj.positive_number = -5  # raises ValueError

4. Dynamically creating an attribute with setattr :

class MyClass:
    pass

obj = MyClass()
setattr(obj, "dynamic_attribute", 10)
print(obj.dynamic_attribute)  # 10

5. Dynamically deleting an attribute with delattr :

class MyClass:
    dynamic_attribute = 10

obj = MyClass()
delattr(obj, "dynamic_attribute")
print(obj.dynamic_attribute)  # raises AttributeError

6. Creating a computed property using the @property decorator:

class Circle:
    def __init__(self, radius):
        self.radius = radius
    @property
    def area(self):
        return 3.14 * self.radius ** 2

circle = Circle(5)
print(circle.area)  # 78.5

7. Using @property together with a setter to control access:

class PositiveNumber:
    def __get__(self, instance, owner):
        return instance.__dict__[self.name]
    def __set__(self, instance, value):
        if value <= 0:
            raise ValueError("Value must be positive")
        instance.__dict__[self.name] = value
    def __set_name__(self, owner, name):
        self.name = name

class MyClass:
    positive_number = PositiveNumber()
    def __init__(self):
        self._positive_number = 0
    @property
    def positive_number(self):
        return self._positive_number
    @positive_number.setter
    def positive_number(self, value):
        self._positive_number = value

obj = MyClass()
obj.positive_number = 10
print(obj.positive_number)  # 10
obj.positive_number = -5  # raises ValueError

8. Dynamically creating a class with type :

MyClass = type("MyClass", (), {"dynamic_attribute": 10})
obj = MyClass()
print(obj.dynamic_attribute)  # 10

9. Dynamically creating a method and attaching it to a class:

def dynamic_method(self):
    print("This is a dynamic method")

MyClass = type("MyClass", (), {"dynamic_method": dynamic_method})
obj = MyClass()
obj.dynamic_method()  # This is a dynamic method

10. Using a metaclass to provide dynamic attributes and methods:

class DynamicAttributes(type):
    def __getattr__(cls, name):
        if name == "dynamic_attribute":
            return "This is a dynamic attribute"
        else:
            raise AttributeError(f"{name} is not found")
    def dynamic_method(cls):
        print("This is a dynamic method")

class MyClass(metaclass=DynamicAttributes):
    pass

obj = MyClass()
print(obj.dynamic_attribute)  # This is a dynamic attribute
obj.dynamic_method()  # This is a dynamic method

These examples illustrate common applications of attribute access and dynamic attributes in Python, and can be adapted or extended for specific needs.

PythonMetaprogrammingdescriptorsDynamicAttributesPropertyDecorator
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.