Checking function calls

Fredrik Tolf fredrik at dolda2000.com
Wed Mar 8 15:11:15 EST 2006


On Mon, 2006-03-06 at 20:25 -0800, James Stroud wrote:
> Fredrik Tolf wrote:
> > If I have a variable which points to a function, can I check if certain
> > argument list matches what the function wants before or when calling it?
> > 
> > Currently, I'm trying to catch a TypeError when calling the function
> > (since that is what is raised when trying to call it with an illegal
> > list), but that has the rather undesirable side effect of also catching
> > any TypeErrors raised inside the function. Is there a way to avoid that?
> > 
> > Fredrik Tolf
> > 
> > 
> 
> Since python is "weakly typed", you will not be able to check what 
> "type" of arguments a function expects. [...]

Sorry, it seems I made myself misunderstood. I don't intend to check the
type of the values that I pass to a function (I'm well aware that Python
is dynamically typed). The reason I refer to TypeError is because that
seems to be the exception raised by Python when I attempt to call a
function with an argument list that wouldn't be valid for it (for
example due to the number of parameters being wrong). I just want to
check in advance whether a certain arglist would be valid to call a
certain function.

> So, if you want to know the number of 
> arguments expected, I've found this works:
> 
> py> def func(a,b,c):
> ...   print a,b,c
> ...
> py> func.func_code.co_argcount
> 3

Not very well, though:
>>> def a(b, c, *d): pass
... 
>>> print a.func_code.co_argcount
2

Here, that would indicate that I could only call `a' with two arguments,
while in fact I could call it with two or more arguments.

More exactly, what I'm trying to do is this; I writing a small protocol
server class as part of a program, and I thought it would be convenient
to be able to define new commands in the protocol by just adding a
function for them, like this:

class client:
    # ...
    # Read is called from the event driver when data is available on the
    # socket.
    def read(self):
        self.buf += self.sk.recv(65536)
        for c in self.buf.split("\n")[:-1]:
            cv = tokenize(c)
            if len(cv) > 0:
                f = getattr(self, "cmd_" + cv[0], None)
                if callable(f):
                    f(*cv[1:])
                else:
                    self.reply("err", "unk")
    # Example:
    def cmd_echo(self, arg1):
        self.reply("ok", arg1)

So basically, I want to be able to handle to client giving the wrong
number of arguments and reply with an error rather than the server
process crashing and dying. Therefore, I'm currently catching TypeErrors
when calling the function:

# ...
if callable(f):
    try:
        f(*cv[1:])
    except TypeError:
        self.reply("err", "argno")
# ...

However, this results in bugs in the server code that would cause
TypeError to reply to the client that it had the wrong number of args,
and I can't see what the real cause is without turning off that check
while debugging. Therefore, I'd like to check in advance whether cv[1:]
would raise a TypeError upon calling f with it or not. And of course,
I'd like to be able to use cmd_* functions with variable arglists as
well.

Surely, there ought to be some way in python to see whether a certain
argument list would be valid for a function call, without checking magic
values of f.func_code?

Fredrik Tolf





More information about the Python-list mailing list