How can I use the decorator pattern in Python to dynamically add methods to a class based on data in a dictionary?

Question:

Consider a scenario where you have a base class Animal and you want to add new methods to the class based on data stored in a dictionary. The data in the dictionary maps method names to functions, and you want to use the decorator pattern to dynamically add these methods to the class.

For example, suppose the dictionary is defined as follows:

methods = {
    "walk": lambda self: print(f"{self.name} is walking"),
    "run": lambda self: print(f"{self.name} is running"),
}

And the base class is defined as:

class Animal:
    def __init__(self, name):
        self.name = name

How can you use the decorator pattern to dynamically add the methods defined in the dictionary to the Animal class?

I tried using a standard decorator to add methods to the class, but this approach only allowed me to add a single method at a time and I couldn’t dynamically add multiple methods based on the data in the dictionary.

I was expecting to find a way to dynamically add the methods to the class based on the data in the dictionary, so that I could add multiple methods to the class in a single line of code. I was looking for a solution that used the decorator pattern as it is a commonly used approach for adding behavior to classes in Python.

Asked By: SoGreatAndPowerful

||

Answers:

methods = {
    "walk": lambda self: print(f"{self.name} is walking"),
    "run": lambda self: print(f"{self.name} is running"),
}


def my_decorator(cls: type):
    for name, method in methods.items():
        setattr(cls, name, method)
    return cls


@my_decorator
class Animal:
    def __init__(self, name):
        self.name = name


animal = Animal("name")
animal.run()

An alternative (decorator factory)

from typing import Callable


methods = {
    "walk": lambda self: print(f"{self.name} is walking"),
    "run": lambda self: print(f"{self.name} is running"),
}


def my_decorator(methods: dict[str, Callable]):
    def decorator(cls: type):
        for name, method in methods.items():
            setattr(cls, name, method)
        return cls
    return decorator


@my_decorator(methods)
class Animal:
    def __init__(self, name):
        self.name = name


animal = Animal("name")
animal.run()
Answered By: WingedSeal
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.