I’ve been reading the python interpreter fairly closely recently (more on that to come in a later blog post), and I was surprised by how much optimisation there is around function calls, dispatching them differently depending on their parameters (expected and supplied)*.
I was going to include this in a later post, but to keep that shorter here’s a quick example. Let’s take these two massively simplified functions.
def a(spam, eggs):
return
def b(spam, eggs=None):
return
Calling a(0,1) is fast because the interpreter skips the keyword argument tests and pushes the parameters direct onto the stack for the new function.
Next came b(0,1) – which takes roughly 10% longer on my machine as there is more for the interpreter to set up.
Calling with keyword arguments is far slower though – with:
a(spam = 0, eggs = 1)
and
b(spam = 0, eggs = 1)
both taking 50% longer than the fastest opportunity (and a negligible difference between the two). Obviously a large part of the 50% increase is setting up the names of the parameters on the stack – but if you read the interpreter source you’ll see there’s far more than that at play (including quick lookup of “self” for bound methods etc.).
(obviously most non-trivial functions will spend a significant time within the function body – which will reduce the relative performance boost – but there’s sure to be the odd situation where it’s worth knowing this.)
* n.b. – I was looking at the 2.5 tag of python, but as far as I can tell none of this code seems to have changed so far in the 3.x trunk.












Look at http://docs.python.org/whatsnew/2.6.html#optimizations for some of the function call and method optimizations that have been made in 2.6.
Whilst this is certainly interesting, I hope it doesn’t cause anyone to opt for less readable code in the hopes that it will give a performance boost. Perhaps if you’re calling a function that (a) does very little work in the body and (b) is called in a loop a few million times, you’ll notice a difference. Otherwise, I’d say that premature optimisation is the root of all evil.
Hanno
- thanks for pointing that out – I’d missed that when checking for changes. It does seem like the difference has been decreased significantly in 2.6 through some clever pointer comparisons.
Martin
- I agree, the only times I think I am likely to choose not to use keyword arguments is in exactly those kinds of situations (parsers, VMs, mathematical code etc.)