Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically defining methods with names derived from a class attribute?

The title might not be the best description of what I'm trying to do but I'm not sure what to call this. I came across various seemingly related concepts with names like "decorators", "descriptors", and "metaclasses" but I don't know which of those approaches (if any) I should investigate further!

Given the following classes:

class AnimalGreeter(object):

    def __init__(self, greeting):
        self.greeting = greeting

    def greet(self, animal):
        print(self.greeting + ", " + animal + "!")

class MyGreeter(AnimalGreeter):

    animals = ['dog', 'parrot']

I'd like to be able to use an instance of MyGreeter like this:

greeter = MyGreeter("What's up")
greeter.parrot
# "What's up, parrot!"

Effectively, I would like it to function as if I had defined MyGreeter like this instead:

class MyGreeter(AnimalGreeter):

    @property
    def dog(self):
        self.greet('dog')

    @property
    def parrot(self):
        self.greet('parrot')

In other words, I want to dynamically define methods (dog(), etc.) with names derived from an attribute (animals) of the class (MyGreeter).

What is the best way to do this? Thanks a lot!

like image 488
tino Avatar asked Mar 11 '26 22:03

tino


1 Answers

An easy way to do this would just be to implement __getattr__(), e.g.:

class MyGreeter(AnimalGreeter):
    animals = {'dog', 'parrot'}

    def __getattr__(self, animal):
        if animal in self.animals:
            return self.greet(animal)
        raise AttributeError("'{}' object unknown animal '{}'".format(type(self).__name__, animal))

>>> greeter = MyGreeter("What's up")
>>> greeter.parrot
What's up, parrot!
>>> greeter.cat
...
AttributeError: 'MyGreeter' object unknown animal 'cat'
like image 148
AChampion Avatar answered Mar 13 '26 13:03

AChampion