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:

1
2
3
4
5
6
7
8
9
10
11
12
13
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:

1
2
3
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:
1
2
3
4
5
6
    @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:

1
2
3
4
5
6
@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.