Python – Why is the “exploded” Python code actually running faster

optimizationpython

I'm in an introductory comp-sci class (after doing web programming for years) and became curious about how much speed I was gaining, if any, with my one-liners.

for line in lines:
  numbers.append(eval(line.strip().split()[0]))

So I wrote the same thing with painfully explicit assignments and ran them against each other.

for line in lines:
  a = line.split()
  b = a[0]
  c = b.strip()
  d = eval(c)
  numbers.append(d)

The second one runs a consistent 30ms faster (on my FreeBSD shell account; see Edit #2) with an input file of 100K lines! Of course this is on a total run time of 3 seconds, so the percentage isn't large…but I'm really surprised to see all those explicit named assignments somehow helping.

There's a recent thread on the performance of functions as opposed to inline code, but this seems even more basic. What gives? Should I be writing lovingly fulsomely verbose code and telling my sneering colleagues it's for performance reasons? (Thankfully, a list-comprehension version runs about 10ms faster yet, so my cherished compactness isn't totally out the window.)

EDIT: Thanks for the tip on my sloppy expansion of the code. You're all correct that the second one should really be:

for line in lines:
  a = line.strip()
  b = a.split()
  c = b[0]
  d = eval(c)
  numbers.append(d)

However, even once I've fixed that, my timings are 2.714s, 2.652s, and 2.624s respectively, for the one-liner, the fully-exploded form, and the list comprehension (not pictured). So my question stands!

EDIT #2: It's interesting that the answer doesn't seem to be obvious even to a bunch of knowledgeable folks, which makes me feel a bit better about the question! I'll probably play with dis a bit on my own now, in this and similar circumstances, and see what turns up. By all means keep tinkering with the thread if you want, but I'm going to declare my received answer to be "huh, that's interesting; must be something deep." Especially since the behavior isn't consistent across machines, as steveha pointed out — the slight difference goes the other direction on my Debian and Windows installs. Thanks to everyone who's contributed!

Best Solution

Your code isn't exploded in the same order. The compact version goes:

A > B > C > D > E 

while your exploded version goes

B > C > A > D > E

The effect is that strip() is being deferred 2 steps down, which may affect performance depending on what the input is.