Partial function is a function partially complete. As a transformer, it is a way to create new functions from existing functions, meanwhile adding your own things. It can be named whatever you want, but I call it
partial to keep consistency with the concept.
Here is a typical implementation of partial function.
def partial(method, name, **specified):
It seems to be pretty complex. This article will help you understand this function.
partial mainly does two things: (1) defines a function and (2) returns that. The function returned is called "wrapper". Before it is returned, the function's name is changed in this line of code
wrapper.__name__ = name
As a result, the parameter
name controls the name of returned function. If you pass "a_fancy_function" to
name then the function returned will be
The first line of function body is a decorator
To those who are not familiar to decorator, you can either spend 15 minutes to read the famous article, or you can just believe the following words:
Decorator is a function that consumes a function and produces a new one to replace the original function.
If we have the following function
func is invoked, instead of execute
func(), the Python interpreter will actually calls
Decorator is achieved via wrapping the original function by another function (inside the decorator). The original function is called "the wrapped function". The function inside decorator is called "wrapper".
As you can imagine, usually a decorator is defined like this.
In our case there is a parameter in the decorator. This can be translated to
functools.wraps takes the parameter
method and returns a function. That function serves as the decorator: modifies and replaces the function
Before moving forward let's summarize the progress so far.
- There is a function called
wrapperwhich does something we haven't known yet.
- The function's name is changed from "wrapper" to the argument passed to
- A decorator is constructed by passing
methodto a function called
- That decorator is used to update the
- A function called
partialprovides an interface for all those activities.
Obviously, we need to know more about
functools.wraps to reveal the meaning of
We have already known how decorator works. This time we want to implement the wrapper. We need to know some information of the wrapped function. Could we achieve that with a decorator? Initially it seems to be a crazy idea, because the wrapped function will then become the wrapper of wrapper. However,
functools.wraps is a special decorator. It is designed to pass the wrapped function to the wrapper.
The function body of
wrapper only contains three lines of code.
def wrapper(self, *args, **kwargs):
The first line is to construct a dictionary for
specified, which is a group of named arguments passed to
update method is called, those named arguments in
kwargs are integrated into
final. New key/value pairs are added and existing keys are overwritten. You will soon know that it is the main purpose of using
Finally a value is returned. Here is the hard part.
You may be confused by the first argument
wrapper. It seems that
wrapper is not inside a class. So why does it contain
self as the first parameter? While, I hope you still remember that
wrapper is the function returned by
partial is used inside a class to generate a group of methods, then definitely we need
self as the first parameter for those methods to work.
Then what does
getattr(self, method.__name__) mean?
getattr is a built-in function to retrieve a named attribute inside an object.
getattr(foo, "bar") is equivalent to
foo.bar. We know
self is an instance of a class,
method is a function, so
getattr(...) returns a function with the same name as
method and invoked on
self instance. Let's call this function "middle". The whole
wrapper returns the execution result of
middle(*args, **final). The key point is that the return of
wrapper is not a function any more! This is the place that does the real work.
Why we spend so much time looking at the crazy
partial function? Because it is really useful! Here is an illustration.
When using a factory to generate instances, it is common to write many methods to produce different things. Among the required parameters, some of them are already known (such as
type), others need to be provided by the clients at runtime. By using partial function, we hide a group of named parameters with default values from the interface, and generate a large amount of class methods in a very compact and efficient way. That's the reason why partial functions are commonly used in real projects.