Using Python introspection for semi-evil
One of the things I write in Python is network daemons. Because it works so nicely, network daemons usually take input as text lines that start with a command word and have whitespace separated arguments. There's a certain amount of eye-rolling tedium in writing code to check that the command word is valid and has the right number of arguments. When I wrote a program that does a lot of this, the tedium finally got to me and I sort of snapped and automated all of the validation through Python's introspection features.
The program's basic structure has an object for each connection. Each command is handled by a method function on the object, and the functions all take normal argument lists. (So they are not passed the command line as a big list or anything.)
The name of each command method is 'op_<command>
', eg
'op_sample
' to handle the 'sample' command. To check whether the
line's first word was a valid command, I just looked to see if the
connection's object had an attribute with the appropriate name.
(This is a fairly common pattern in Python; see, for example, how
BaseHTTPServer
handles dispatching GET
and POST
and so on.)
To check that the number of arguments was right, I reached into the handler function I'd just found and fished out how many arguments it expected to be called with (compensating for the additional 'self' argument that method functions get). This isn't at all general, but I didn't need generality; the network daemon's commands all have a fixed number of arguments.
The code wound up looking like this:
# in a class: def op_sample(self, one, two): ... def dispatch(self, line): # Do we have a line at all? n = line.split() if not n: return False cword = 'op_' + n[0] # Valid command word? cfunc = getattr(self, cword, None) if not cfunc: return False # Right argument count? acnt = cfunc.func_code.co_argcount if acnt != len(n) return False return cfunc(*n[1:])
(The real version used more elaborate error handling for 'empty line', 'no such command', and 'wrong number of arguments'.)
Normally I would have to account for the extra self
argument in the
function's argument count. But in this code the n
list has one
extra element (the command word) too, so it balances out. This has the
subtle consequence that you can't make op_sample
a staticmethod
function, because then it would have the wrong argument count.
(I did say this was semi-evil.)
Comments on this page:
|
|