["python","functional-programming","currying","functools","partial-application"]
How does functools partial do what it does?

I am not able to get my head on how the partial works in functools. I have the following code from here: >>> sum = lambda x, y : x + y >>> sum(1, 2) 3 >>> incr = lambda y : sum(1, y) >>> incr(2) 3 >>> def sum2(x, y): return x + y >>> incr2 = functools.partial(sum2, 1) >>> incr2(4) 5 Now in the line incr = lambda y : sum(1, y) I get that whatever argument I pass to incr it will be passed as y to lambda which will return sum(1, y) i.e 1 + y. I understand that. But I didn't understand this incr2(4). How does the 4 gets passed as x in partial function? To me, 4 should replace the sum2. What is the relation between x and 4?
Roughly, partial does something like this (apart from keyword args support, etc): def partial(func, *part_args): def wrapper(*extra_args): return func(*part_args, *extra_args) return wrapper So, by calling partial(sum2, 4) you create a new function (a callable, to be precise) that behaves like sum2, but has one positional argument less. That missing argument is always substituted by 4, so that partial(sum2, 4)(2) == sum2(4, 2) As for why it's needed, there's a variety of cases. Just for one, suppose you have to pass a function somewhere where it's expected to have 2 arguments: class EventNotifier(object): def __init__(self): self._listeners = [] def add_listener(self, callback): ''' callback should accept two positional arguments, event and params ''' self._listeners.append(callback) # ... def notify(self, event, *params): for f in self._listeners: f(event, params) But a function you already have needs access to some third context object to do its job: def log_event(context, event, params): context.log_event("Something happened %s, %s", event, params) So, there are several solutions: A custom object: class Listener(object): def __init__(self, context): self._context = context def __call__(self, event, params): self._context.log_event("Something happened %s, %s", event, params) notifier.add_listener(Listener(context)) Lambda: log_listener = lambda event, params: log_event(context, event, params) notifier.add_listener(log_listener) With partials: context = get_context() # whatever notifier.add_listener(partial(log_event, context)) Of those three, partial is the shortest and the fastest. (For a more complex case you might want a custom object though).