Search code examples
pythondecoratorsetattr

How to use setattr to create bound methods?


So I have a class with a method, which takes string. Somethinkg like this:

class A():

    def func(self, name):
        # do some stuff with it

I have finite number of possible values, [val1, val2, val2] for example, All strings. I want to use them like this:

a = A()
a.val1() # actually a.func(val1)

I tried to combine decorators and setattr:

class A():

    def func(self, val):
        # do some stuff with it

    def register(self, val):
        def wrapper(self):
            self.func(val)

        setattr(self, val, wrapper)

So I can iterate through all possible values in run-time:

a = A()
for val in vals:
    a.register(val)

And it has zero effect. Usually setattr adds new attribute with value None, but in this case nothing happens. Can somebody explain why it is this way and what can I do?


Solution

  • register() isn't a decorator, it's mostly just a "function factory" with side-effects. Also, as I said in a comment, setattr() needs to know what name to assigned to the value.

    Here's a way to get your code to work:

    class A():
    
        def func(self, val):
            # do some stuff with it
            print('func({}) called'.format(val))
    
        def register(self, val, name):
            def wrapper():
                self.func(val)
            wrapper.__name__ = name
            setattr(self, name, wrapper)
    
    vals = 10, 20, 30
    a = A()
    
    for i, val in enumerate(vals, 1):
        a.register(val, 'val'+str(i))  # Creates name argument.
    
    a.val1()  # -> func(10) called
    a.val2()  # -> func(20) called