Add hash/eq built-ins to functools.partial

Tricks like caching function results don’t work when you can’t check whether two function calls are identical.

>>> a=partial(int,1.23)
>>> b=partial(int,1.23)
>>> a==b
>>> hash(a)
>>> hash(b)

Thus I’d like to add suitable __hash__ and __eq__ built-ins to functools.partial.


How do you decide whether two function calls are identical?

We might argue that if all of the arguments to partial are identical (not just equal), then two calls to partial(func, *args, **kw) should return two partial objects which compare equal.

But if you are doing that, why bother with the two calls to partial?

x = 1.23
a = partial(int, x)
b = partial(int, x)  # arguments are identical

# But this is simpler:
a = b = partial(int, x)

Under what real life circumstances would this make a difference?

This is similar to the situation with function objects themselves, which also compare by identity. Determining whether two arbitrary function calls are identical is hard to do programmatically:

def f(n:int) -> int:
    return sum(range(1, n+1))

def g(m:int) -> int:
    return 0 if m < 0 else m*(m+1)//2

Assuming int inputs only, f and g are equivalent but it would be hard for the interpreter to know that.

We might simplify the requirement to only require equivalent ASTs. If two functions have “the same” source code, ignoring comments, non-significant whitespace and variable names, and so generate the same AST and hence the same byte-code, we could consider those two functions equal:

(lambda x: x+1) == (lambda y: y + 1)

This currently returns False but it could return True. That might be nice.

But is it worth the effort? Under what circumstances in real life would it actually make a difference?

I’m sympathetic to this suggestion. It hurts my sense of aesthetics that two function objects with identical source code, which therefore do exactly the same thing, are not considered equal. And likewise for partial objects.

But without a stronger justification than just aesthetics, I can hardly expect other people to do the work, including maintenance of the code forever. Not just for CPython, but for any other Python interpreter as well.