Python: how to use lambda or partial to bind arguments other than the first positional argument

I have a lot of confusion in trying to use either lambda or functools.partial to create a new function with related positional arguments from an existing function.

I want to do something like this (which does not behave as desired):

 def addFunction(self, name, in_function, secondary_args=None, secondary_kwargs=None): # Assign the function with optional args based on whether any # optional args are not None if secondary_args is not None and secondary_kwargs is not None: func = lambda x: in_function(x, *secondary_args, **secondary_kwargs) elif secondary_args is None and secondary_kwargs is not None: func = lambda x: in_function(x, **secondary_kwargs) elif secondary_args is not None and secondary_kwargs is None: func = lambda x: in_function(x, *secondary_args) else: func = in_function ### func.__doc__ = in_function.__doc__ self[name] = func # <-- This method is a class method for something deriving dict. 

I also tried replacing all lambda statements with equivalent functools.partial .

The problem is that if I use this function as follows:

 # Assume some_function takes 3 arguments, a float, a Bool, and a String, # in that order. someObject.addFunction("my_f", some_function, secondary_args=[True, "Option_A"]) 

now when I try to use (for example) someObject["my_f"](5.0) , it reports that the first argument is True when I debug it.

It seems that the bindings, either with lambda or with partial simply insert positional arguments and either take your extra positional argument at the end of *args , or just discard it (I'm not sure which one).

For my application, since many functions will be stored in a specific object like this, with a different number of optional arguments chosen by the user, it is important that the function I return with bound arguments still accepts the user argument as the first positional argument, without resorting to all arguments were keyword arguments.

It seems like it should be simple enough. What am I missing?

+6
source share
2 answers

Can you post a complete script that reproduces the error? Since the following script works as expected:

 class C(dict): def addFunction(self, name, in_function, secondary_args=None, secondary_kwargs=None): # Assign the function with optional args based on whether any # optional args are not None if secondary_args is not None and secondary_kwargs is not None: func = lambda x, *secondary: in_function(x, *secondary_args, **secondary_kwargs) elif secondary_args is None and secondary_kwargs is not None: func = lambda x: in_function(x, **secondary_kwargs) elif secondary_args is not None and secondary_kwargs is None: func = lambda x: in_function(x, *secondary_args) else: func = in_function ### func.__doc__ = in_function.__doc__ self[name] = func # <-- This method is a class method for something deriving dict. def f(x, y=0, z=1): print x, y, zc = C() c.addFunction('my_f', f, secondary_args=[-1]) c['my_f'](0) # output is 0 -1 1, as expected 

Maybe the problem is how you "attach" a function to your object?

+1
source

It sounds like you just need some kind of custom shell type:

 class Caller(object): def __init__(self, fn, *args, **kwargs): self._fn = fn self._args = args self._kwargs = kwargs def __call__(self, *uargs, **ukwargs): arg = uargs + self._args kw = dict(ukwargs.items() + self._kwargs.items()) self._fn(*arg, **kw) 

And then wrap something:

 def test(a,b,c=None): print a,b,c c = Caller(test, 2,c=True) c(1) # 1 2 True 

I'm sure Caller could have been cleaned up, but it was just a quick example of how to store the original fn and params and then control when it is called.

0
source

Source: https://habr.com/ru/post/922226/


All Articles