5

Recently, I had to convert the values of a dictionary to a list in Python 3.6 and an use case where this is supposed to happen a lot.
Trying to be a good guy I wanted to use a solution which is close to the PEP. Now, PEP 3106 suggests

list(d.keys())

which obviously works fine - but using timeit on my Windows 7 machine i see

>python -m timeit "[*{'a': 1, 'b': 2}.values()]"
1000000 loops, best of 3: 0.249 usec per loop

>python -m timeit "list({'a': 1, 'b': 2}.values())"
1000000 loops, best of 3: 0.362 usec per loop

I assume that there is an advantage in the latter version, because why else should the PEP suggest the slower one.

So here comes my question: What's the advantage of the latter version compared to the first one?

d4tm4x
  • 190
  • 1
  • 10
  • 1
    PEP 3106 was written before the first syntax existed in Python. I would be surprised if the performance difference there could be relied upon - I can't see a reason the first one should be have better performance. – Gareth Latty Mar 20 '18 at 12:29
  • 3
    Does this performance matter to you? If so, why? There are many, *many* occasions when you can find trivially optimisable variants of code in PEP. Micro-optimization is not a purpose of PEP. – jpp Mar 20 '18 at 12:30
  • @GarethLatty this more than 45% increase in runtime. For my impression too much to be coincidence. – d4tm4x Mar 20 '18 at 12:33
  • 1
    @jpp To be honest, I don't think that this "micro-optimization" (very nice term, I like it) matters at all. I was just curious, since I'm not a "real" programmer and wanted to see a comparison between the solutions. – d4tm4x Mar 20 '18 at 12:35
  • 1
    @month I've added a performance section to my answer, you are using too simple a test to claim a 45% increase. My guess is it's the cost of looking up the `list` name (which could be rebound), vs the list literal which can't. – Gareth Latty Mar 20 '18 at 12:48

1 Answers1

10

The answer is because the faster syntax was first introduced in PEP 448 in 2013, while PEP 3106 you reference was written in 2006, so even if is faster in a real way now, it didn't exist when the PEP was written.

As noted by others, the role of PEPs is not to provide a template for the fastest possible code - in general, code in PEPs will aim to be simpler and as clear as possible, because examples are generally about understanding concepts rather than achieving the best possible results, so even if the syntax did exist at the time, and is faster in a real (and reliable) way, it still may not have been used.

A bit of further testing with larger values:

python -m timeit -s "x = [1]*10000" "[*x]"                
10000 loops, best of 3: 44.6 usec per loop

python -m timeit -s "x = [1]*10000" "list(x)" 
10000 loops, best of 3: 44.8 usec per loop

Shows the difference isn't really two times, but rather a flat cost - I would guess it's the cost of looking up the list() built-in function. This is negligible in most real cases.

Gareth Latty
  • 77,968
  • 15
  • 168
  • 174