Search code examples
pythonfunctools

Returning a functools.partial from a function accepting any arguments


I need to create a mock-method that stores any arguments passed to it, so I can later assert it was called correctly. To do that I need to create functions from the mock-objects store function, so that I can return anything I want but store all parameters. The MWE of what I am trying to do looks like this:

import functools
f1 = lambda test, *a, **b: print(a, b, test)
f2 = functools.partial(f1, test=42)
f2(2,3,a=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: <lambda>() got multiple values for argument 'test'

Is it possible to get this working? In essence I need f2 to accept any number of positional or keyword_arguments, but have the argument test already defined as input for f1.

I want the above call to f2 print:

(2, 3) {'a': 4} 42

or similar, it's important that test can be used in f1 but doesn't have to be set/is already predefined for f2.


Solution

  • You can do

    import functools
    f1 = lambda test, *a, **b: print(a, b, test)
    f2 = functools.partial(f1, 42)
    f2(2, 3, a=4)
    

    output:

    (2, 3) {'a': 4} 42
    

    Note that using lambda in this case is not in line with PEP8 recommendations. Use regular function instead:

    Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier:

    # Correct: def f(x): return 2*x
     
    # Wrong: f = lambda x: 2*x
    

    The first form means that the name of the resulting function object is specifically 'f' instead of the generic ''. This is more useful for tracebacks and string representations in general. The use of the assignment statement eliminates the sole benefit a lambda expression can offer over an explicit def statement (i.e. that it can be embedded inside a larger expression)