92

I have a number of functions with a combination of positional and keyword arguments, and I would like to bind one of their arguments to a given value (which is known only after the function definition). Is there a general way of doing that?

My first attempt was:

def f(a,b,c): print a,b,c

def _bind(f, a): return lambda b,c: f(a,b,c)

bound_f = bind(f, 1)

However, for this I need to know the exact args passed to f, and cannot use a single function to bind all the functions I'm interested in (since they have different argument lists).

0

4 Answers 4

154
>>> from functools import partial
>>> def f(a, b, c):
...   print a, b, c
...
>>> bound_f = partial(f, 1)
>>> bound_f(2, 3)
1 2 3
Sign up to request clarification or add additional context in comments.

3 Comments

Is there a way to use partial if you wanted to bind the second or third argument?
You can bind all arguments bound_f = partial(f, 1, 2, 3) and then call bound_f()
@MarkRansom You can use named arguments to bind any argument. Example: partial(f, b=2).
21

You probably want the partial function from functools.

Comments

18

As suggested by MattH's answer, functools.partial is the way to go.

However, your question can be read as "how can I implement partial". What your code is missing is the use of *args, **kwargs- 2 such uses, actually:

def partial(f, *args, **kwargs):
    def wrapped(*args2, **kwargs2):
        return f(*args, *args2, **kwargs, **kwargs2)
    return wrapped

1 Comment

If you're going to use this on very old python versions (in my case Jython 2.1) and this gives a SyntaxError: invalid syntax on *args2 just merge args/args2 and kwargs/kwargs2. My solution was the following (lines after wrapped(...)): new_args = args + args2 followed by new_kwargs = kwargs.copy() and new_kwargs.update(kwargs2). Then change the returned function line to return f(*new_args, **new_kwargs). It will work with no problems
8

You can use partial and update_wrapper to bind arguments to given values and preserve __name__ and __doc__ of the original function:

from functools import partial, update_wrapper


def f(a, b, c):
    print(a, b, c)


bound_f = update_wrapper(partial(f, 1000), f)

# This will print 'f'
print(bound_f.__name__)

# This will print 1000, 4, 5
bound_f(4, 5)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.