How to test that functools.partial produces the expected function object

arguments, functools, python, unit-testing

Solution

The `func` attribute on the `partial()` object is a reference to the original function object:

f1.func is f2.func

Function objects themselves don't implement a `__eq__` method, so you may as well just use `is` to test for identity.

Similarly, the `partial().args` and `partial().keywords` contain the arguments and keyword arguments to be passed to the function when called.

Demo:

>>> from functools import partial
>>> def foo(a, b):
...     return a + b
... 
>>> f1 = partial(foo, 2)
>>> f2 = partial(foo, 2)
>>> f1.func is f2.func
True
>>> f1.args
(2,)
>>> f2.args
(2,)
>>> f1.keywords is None
True
>>> f2.keywords is None
True

Problem

When going from one API to another it can sometimes be helpful to map between similar keywords in each API, allowing one controller API to flexibly dispatch to other libraries without needing the user to fuss around with the different API's under the hood. Assume some library, `other_api`, has a method called `"logarithm"`, and the keyword argument for the base is something I need to factor out of my code, like `"log_base_val"`; so that to use it from `other_api` I need to type (for example): ``` other_api.logarithm(log_base_val=math.e) ``` Consider a toy class like this: ``` import other_api import math import functools class Foo(object): _SUPPORTED_ARGS = {"base":"log_base_val"} def arg_binder(self, other_api_function_name, **kwargs): other_api_function = getattr(other_api, other_api_function_name) other_api_kwargs = {_SUPPORTED_ARGS[k]:v for k,v in kwargs.iteritems()} return functools.partial(other_api_function, **other_api_kwargs) ``` With `Foo`, I can map some other API, where this argument is always called `base`, like this: ``` f = Foo() ln = f.arg_binder("logarithm", base=math.e) ``` and `ln` is logically equivalent to (with `log_base_val=math.e` in `kwargs`, from `functools`): ``` other_api.logarithm(*args, **kwargs) ``` However, manually making the same argument bind by invoking `functools` will lead to different function objects: ``` In [10]: import functools In [11]: def foo(a, b): ....: return a + b ....: In [12]: f1 = functools.partial(foo, 2) In [13]: f2 = functools.partial(foo, 2) In [14]: id(f1) Out[14]: 67615304 In [15]: id(f2) Out[15]: 67615568 ``` So testing for `f1 == f2` won't succeed as intended: ``` In [16]: f1 == f2 Out[16]: False ``` So the question is: what is the prescribed way to test whether the argument binding function has resulted in the correct output function object?

Original source