Is there a way to invoke a Python function with the wrong number of arguments without invoking a TypeError?

StackOverflow https://stackoverflow.com/questions/933484

  •  06-09-2019
  •  | 
  •  

Question

When you invoke a function with the wrong number of arguments, or with a keyword argument that isn't in its definition, you get a TypeError. I'd like a piece of code to take a callback and invoke it with variable arguments, based on what the callback supports. One way of doing it would be to, for a callback cb, use cb.__code__.cb_argcount and cb.__code__.co_varnames, but I would rather abstract that into something like apply, but that only applies the arguments which "fit".

For example:

 def foo(x,y,z):
   pass

 cleanvoke(foo, 1)         # should call foo(1, None, None)
 cleanvoke(foo, y=2)       # should call foo(None, 2, None)
 cleanvoke(foo, 1,2,3,4,5) # should call foo(1, 2, 3)
                           # etc.

Is there anything like this already in Python, or is it something I should write from scratch?

Was it helpful?

Solution

Rather than digging down into the details yourself, you can inspect the function's signature -- you probably want inspect.getargspec(cb).

Exactly how you want to use that info, and the args you have, to call the function "properly", is not completely clear to me. Assuming for simplicity that you only care about simple named args, and the values you'd like to pass are in dict d...

args = inspect.getargspec(cb)[0]
cb( **dict((a,d.get(a)) for a in args) )

Maybe you want something fancier, and can elaborate on exactly what?

OTHER TIPS

This maybe?

def fnVariableArgLength(*args, **kwargs):
    """
    - args is a list of non keywords arguments
    - kwargs is a dict of keywords arguments (keyword, arg) pairs
    """
    print args, kwargs


fnVariableArgLength() # () {}
fnVariableArgLength(1, 2, 3) # (1, 2, 3) {}
fnVariableArgLength(foo='bar') # () {'foo': 'bar'}
fnVariableArgLength(1, 2, 3, foo='bar') # (1, 2, 3) {'foo': 'bar'}

Edit Your use cases

def foo(*args,*kw):
    x= kw.get('x',None if len(args) < 1 else args[0])
    y= kw.get('y',None if len(args) < 2 else args[1])
    z= kw.get('z',None if len(args) < 3 else args[2])
    # the rest of foo

foo(1)         # should call foo(1, None, None)
foo(y=2)       # should call foo(None, 2, None)
foo(1,2,3,4,5) # should call foo(1, 2, 3)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top