Search code examples
pythonoverridingpartialfunctools

partial: disallow overriding given keyword arguments


Is there a way to disallow overriding given keyword arguments in a partial? Say I want to create function bar which always has a set to 1. In the following code:

from functools import partial

def foo(a, b):
  print(a)
  print(b)

bar = partial(foo, a=1)
bar(b=3) # This is fine and prints 1, 3
bar(a=3, b=3) # This prints 3, 3

You can happily call bar and set a to 3. Is it possible to create bar out of foo and make sure that calling bar(a=3, b=3) either raises an error or silently ignores a=3 and keeps using a=1 as in the partial?


Solution

  • This is by design. The documentation for partial says (emphasize mine):

    functools.partial(func, /, *args, **keywords)
    

    Return a new partial object which when called will behave like func called with the positional arguments args and keyword arguments keywords. If more arguments are supplied to the call, they are appended to args. If additional keyword arguments are supplied, they extend and override keywords.

    If you do not want that, you can manually reject frozen keyword arguments:

    def freeze(f, **kwargs):
        frozen = kwargs
        def wrapper(*args, **kwargs):
            kwargs.update(frozen)
            return f(*args, **kwargs)
        return wrapper
    

    You can now do:

    >>> baz = freeze(foo, a=1)
    >>> baz(b=3, a=2)
    1
    3