Using functools.partial instead of saving arguments

I’m a big fan of functools.partial myself. It allows you to take a function, preset some of its arguments and return another function which you can call with more arguments. Not sure if currying is the right term here, but I’ve heard people refer to functools.partial like that.

Today while browsing the source code for the futures module I came across this class:

[gist]https://gist.github.com/4048428[/gist]

The moment I saw that func, args and kwargs were saved as attributes in the instance I thought: “why not use partial and save a single attribute?”. Then I thought that maybe performance had something to do here, so I wrote a dead simple stupid test to check it out:

[gist]https://gist.github.com/4048405[/gist]

Here are the results using CPython 2.7.3:

In [3]: %timeit testpartial.do_test(testpartial.WorkItem)
100000 loops, best of 3: 5.26 us per loop

In [4]: %timeit testpartial.do_test(testpartial.WorkItemPartial)
100000 loops, best of 3: 2.65 us per loop

We are talking microseconds here, but still the version with partial is almost twice as fast.

Now, lets see how PyPy performs:

In [9]: %timeit -n 10000 testpartial.do_test(testpartial.WorkItem)
10000 loops, best of 3: 154 ns per loop
Compiler time: 554050.78 s

In [10]: %timeit -n 10000 testpartial.do_test(testpartial.WorkItemPartial)
10000 loops, best of 3: 2.49 us per loop

Fun, the version without partial goes into the nanoseconds! And the one with partial doesn’t improve much with regards to CPython. Interesting.

So what’s the take here? Well, whenever I see fit I use partial, code looks nicer and it’s apparently faster, so why not? 🙂

:wq

4 thoughts on “Using functools.partial instead of saving arguments

  1. It is a bit less readable for the not so fond of functional programming right? I guess it is a trader off between code complexity and performance.

  2. Pypy 2.1 (please note that the order of the tests is changed)

    In [2]: %timeit testpartial.do_test(testpartial.WorkItemPartial)

    1000000 loops, best of 3: 535 ns per loop

    In [3]: %timeit testpartial.do_test(testpartial.WorkItem)

    10000000 loops, best of 3: 58.5 ns per loop

    1. Interesting 🙂 Still, saving a stack frame is nice for traceback printing 😉

Leave a Reply

Your email address will not be published.