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.