[Python-Dev] PEP 309

Paul Moore p.f.moore at gmail.com
Sat Feb 26 22:52:51 CET 2005


On Sat, 26 Feb 2005 13:20:46 -0500, Raymond Hettinger
<raymond.hettinger at verizon.net> wrote:
> It is better to teach how to write a closure than to introduce a new
> construct that has its own problems and doesn't provide a real
> improvement over what we have now.

You make some good points. But this all reminds me of the discussion
over itemgetter/attrgetter. They also special-case particular uses of
lambda, and in those cases the stated benefits were speed and
(arguably) readability (I still dislike the names, personally).

I think partial hits a similar spot - it covers a fair number of
common cases, and the C implementation is quoted as providing a speed
advantage over lambda. On the minus side, I'm not sure it covers as
many uses as {item,attr}getter, but on the plus side, I like the name
better :-) Seriously, not needing to explicitly handle *args and **kw
is a genuine readability benefit of partial.

Of course, optimising Python function calls, and optimising lambda to
death, would remove the need for any of these discussions. But there's
no real indication that this is likely in the short term...

This got me thinking, so I did a quick experiment:

>python -m timeit -s "from operator import itemgetter; l=range(8)"
"itemgetter(1)(l)"
1000000 loops, best of 3: 0.548 usec per loop

>python -m timeit -s "l=range(8)" "(lambda x:x[1])(l)"
1000000 loops, best of 3: 0.597 usec per loop

That's far less of a difference than I expected from itemgetter! The
quoted speed improvement in the C implementation of partial is far
better... So I got worried, and tried a similar experiment with the C
implementation of the functional module:

>python -m timeit -s "import t" "t.partial(t.f, 1, 2, 3, a=4, b=5)(6,
7, 8, c=9, d=10)"
100000 loops, best of 3: 3.91 usec per loop

>python -m timeit -s "import t" "(lambda *args, **kw: t.f(1, 2, 3,
a=4, b=5, *args, **kw))(6, 7, 8, c=9, d=10)"
100000 loops, best of 3: 3.6 usec per loop

[Here, t is just a helper which imports partial, and defines f as def
f(*args, **kw): return (args, kw)]

Now I wonder. Are my tests invalid, did lambda get faster, or is the
"lambda is slow" argument a myth?

Hmm, I'm starting to go round in circles here. I'll post this as it
stands, with apologies if it's incoherent. Blame it on a stinking cold
:-(

Paul.


More information about the Python-Dev mailing list