views:

146

answers:

2

Is there a possibility to check if two python functions are interchangeable? For instance, if I have

def foo(a, b):
    pass
def bar(x, y):
    pass
def baz(x,y,z):
    pass

I would like a function is_compatible(a,b) that returns True when passed foo and bar, but False when passed bar and baz, so I can check if they're interchangeable before actually calling either of them.

+3  A: 

Take a look at inspect.getargspec():

inspect.getargspec(func)

Get the names and default values of a function’s arguments. A tuple of four things is returned: (args, varargs, varkw, defaults). args is a list of the argument names (it may contain nested lists). varargs and varkw are the names of the * and ** arguments or None. defaults is a tuple of default argument values or None if there are no default arguments; if this tuple has n elements, they correspond to the last n elements listed in args.

Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs, keywords, defaults).

Georg
oh very nice... exactly what I needed. Thanks!
Dave Vogt
+4  A: 

What would you be basing the compatibility on? The number of arguments? Python has variable length argument lists, so you never know if two functions might be compatible in that sense. Data types? Python uses duck typing, so until you use an isinstance test or similar inside the function, there is no constraint on data types that a compatibility test could be based on.

So in short: No.

You should rather write good docstrings, such that any user of your API knows what the function he is giving you has to do, and then you should trust that the function you get behaves correctly. Any "compatibility" check would either rule out possibly valid functions or give you a false sense of "everything is exactly as it should be."

The pythonic way of exposing an API is: Write good documentation, such that people know what they need to know, and trust that they do the right thing. In critical positions you can still use try: except:, but anybody who is misusing your API because they just didn't care to read the doc shouldn't be given a false sense of security. And someone who did read your doc and wants to use it in a totally acceptable way should not be denied the possibility to use it on the grounds of the way they declared a function.

balpha
Yes, number of arguments. I know I can't check for much more, but I think it's nice to the user of the module to reject a given method/function as early as possible (it's a simple event handling mechanism)
Dave Vogt
But this way you will reject a possibly perfectly valid function just because it's declared as def func(*args) or def func(a,b,foo="default"). Just keep that in mind.
balpha
@balpha: this can be checked too using inspect.getargspec. It reports if there are *args and **kwargs arguments.
Georg
Yes, but you would end up with no information at all. I have edited my answer to hopefully make my statement a little bit clear.
balpha
... little bit clearer.
balpha
+1, you have a very valid point that should at least be thought about before implementing such a feature.
Georg