Interview Questions, Answers and Tutorials

Class decorators and metaprogramming

Class decorators and metaprogramming

Imagine you have a magic wand that can change how things behave without actually touching them. In Python, class decorators and metaprogramming are like that magic wand. They let us modify or enhance classes and their behavior in clever ways.

Class Decorators

A class decorator is a function that takes a class and returns a new class with some modifications. It’s like adding superpowers to your class without changing its original code.

How to Use Class Decorators
  1. Define a Decorator Function: A decorator function takes a class as an argument, modifies it, and returns the new class.
  2. Apply the Decorator to a Class: You use the @ symbol to apply the decorator to the class.
Example

Let’s say we have a simple class that greets people:

class Greeter:
    def greet(self, name):
        return f"Hello, {name}!"

# Define a decorator
def add_super_greet(cls):
    cls.super_greet = lambda self, name: f"Hello, Super {name}!"
    return cls

# Apply the decorator
@add_super_greet
class Greeter:
    def greet(self, name):
        return f"Hello, {name}!"

# Create an instance of Greeter
greeter = Greeter()

# Use the methods
print(greeter.greet("Alice"))       # Output: Hello, Alice!
print(greeter.super_greet("Alice")) # Output: Hello, Super Alice!




Here, add_super_greet is a decorator who adds a new method super_greet to the Greeter class.

Metaprogramming

Metaprogramming is like programming that writes or modifies other programs. In Python, this often involves creating classes dynamically or modifying them at runtime.

Metaclasses

A metaclass is a class of a class. It defines how a class behaves. You can use metaclasses to customize class creation.

How to Use Metaclasses
  1. Define a Metaclass: A metaclass is usually a subclass of type.
  2. Use the Metaclass in a Class: You specify the Metaclass in the class definition.
Example

Let’s create a metaclass that automatically adds a super_greet method to any class that uses it:

class SuperGreeterMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs['super_greet'] = lambda self, name: f"Hello, Super {name}!"
        return super().__new__(cls, name, bases, attrs)

class Greeter(metaclass=SuperGreeterMeta):
    def greet(self, name):
        return f"Hello, {name}!"

# Create an instance of Greeter
greeter = Greeter()

# Use the methods
print(greeter.greet("Alice"))       # Output: Hello, Alice!
print(greeter.super_greet("Alice")) # Output: Hello, Super Alice!




Here, SuperGreeterMeta is a metaclass that adds a super_greet method to any class that uses it.

Practice Questions

  1. Create a Class Decorator: Write a class decorator add_farewell that adds a method farewell to a class. The farewell method should return Goodbye, {name}!.
  2. Create a Metaclass: Write a Metaclass FarewellMeta that adds a method farewell to any class that uses it. The farewell method should return Goodbye, {name}!.
Solutions
  1. Class Decorator Solution:
def add_farewell(cls):
    cls.farewell = lambda self, name: f"Goodbye, {name}!"
    return cls

@add_farewell
class Greeter:
    def greet(self, name):
        return f"Hello, {name}!"

# Create an instance of Greeter
greeter = Greeter()

# Use the methods
print(greeter.greet("Alice"))    # Output: Hello, Alice!
print(greeter.farewell("Alice")) # Output: Goodbye, Alice!




  1. Metaclass Solution:
class FarewellMeta(type):
    def __new__(cls, name, bases, attrs):
        attrs['farewell'] = lambda self, name: f"Goodbye, {name}!"
        return super().__new__(cls, name, bases, attrs)

class Greeter(metaclass=FarewellMeta):
    def greet(self, name):
        return f"Hello, {name}!"

# Create an instance of Greeter
greeter = Greeter()

# Use the methods
print(greeter.greet("Alice"))    # Output: Hello, Alice!
print(greeter.farewell("Alice")) # Output: Goodbye, Alice!




Class decorators and metaprogramming in Python are powerful tools that let you modify and enhance classes in creative ways. With class decorators, you can add new methods or attributes to classes. With metaprogramming and metaclasses, you can customize class creation and behavior at a deeper level.