generate object methods at runtime

I have been working on a dialer button class since yesterday. It makes sense to use the command design pattern here, and I want to separate the commands and the buttons so I can change the functionality of every button at runtime.

So we are talking about something like this:

class DialerButtons:
    def __init__(self):
        self.command_table = [
            self.numpad_1, self.numpad_2, self.numpad_3,
            self.numpad_4, self.numpad_5, self.numpad_6,
            self.numpad_7, self.numpad_8, self.numpad_9,
            self.cancel, self.numpad_0, self.dial]

    def numpad_0(self):
        self.text.append('0')

    def execute(self, n):
        self.command_table[n]()

and you can use this class like this:

dialer = DialerButtons()
dialer.execute(0)
dialer.execute(8)

Now obviously define numpad_0 to numpad_9 is a boring task. What happens if you need to define numpad 0 to 99? So, I came out with this code piece:

    @classmethod
    def _numpad_commands_factory(cls):
        for n in xrange(0, 10):
            setattr(cls, 'numpad_%d' % n, lambda self: self.text.append(str(n)))

DialerButtons._numpad_commands_factory()

This way you initialize DialerButtons AFTER you start the program and make methods numpad_0 to 9 on the fly. At least that’s what I was trying to do. However, it didn’t come out as I expected. Every numpad method will just add ‘9’ to self.text, instead of the respective ‘0’ to ‘9’. Why?

The reason is that the context of numpad_0, for example, is actually “f(self): self.text.append(str(n)))” instead of “f(self): self.text.append(‘0’)”. so, what it does here is that it refers to the variable n inside _numpad_commands_factory, and the value of n is 9 after you executed it.

The correct code piece is:

    @classmethod
    def _numpad_commands_factory(cls):
        def f(chr):
            return lambda self: self.text.append(chr)
        for n in xrange(0, 10):
            setattr(cls, 'numpad_%d' % n, f(str(n)))

This way we can evaluate the value of str(n) first, then generate the appropriate function and assign it to numpad_n.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s