Search code examples
pythonpartial-application

How can I bind arguments to a function in Python?


How can I bind arguments to a Python function so that I can call it later without arguments (or with fewer additional arguments)?

For example:

def add(x, y):
    return x + y

add_5 = magic_function(add, 5)
assert add_5(3) == 8

What is the magic_function I need here?


It often happens with frameworks and libraries that people accidentally call a function immediately when trying to give arguments to a callback: for example on_event(action(foo)). The solution is to bind foo as an argument to action, using one of the techniques described here. See for example How to pass arguments to a Button command in Tkinter? and Using a dictionary as a switch statement in Python.

Some APIs, however, allow you to pass the to-be-bound arguments separately, and will do the binding for you. Notably, the threading API in the standard library works this way. See thread starts running before calling Thread.start. If you are trying to set up your own API like this, see How can I write a simple callback function?.

Explicitly binding arguments is also a way to avoid problems caused by late binding when using closures. This is the problem where, for example, a lambda inside a for loop or list comprehension produces separate functions that compute the same result. See What do lambda function closures capture? and Creating functions (or lambdas) in a loop (or comprehension).


Solution

  • functools.partial returns a callable wrapping a function with some or all of the arguments frozen.

    import sys
    import functools
    
    print_hello = functools.partial(sys.stdout.write, "Hello world\n")
    
    print_hello()
    
    Hello world
    

    The above usage is equivalent to the following lambda.

    print_hello = lambda *a, **kw: sys.stdout.write("Hello world\n", *a, **kw)