6

I guess everyone knows that:

Python accesses local variables much more efficiently than global variables

Ok, it's true:

oldlist = [str(i) for i in range(500)]
oldlist1 = [i for i in range(500)]

%%timeit
newlist = []
for word in oldlist:
    newlist.append(word.upper())

10000 loops, best of 3: 178 µs per loop

%%timeit
def func():
    newlist = []
    for word in oldlist:
        newlist.append(word.upper())
    return newlist
newlist = func()

10000 loops, best of 3: 93.2 µs per loop

Unfortunately, looks like it isn't global rule but special case:

%%timeit
newlist = []
for nr in oldlist1:
    newlist.append(nr * nr)

10000 loops, best of 3: 60.3 µs per loop

%%timeit
def func():
    newlist = []
    for nr in oldlist1:
        newlist.append(nr * nr)
    return newlist
newlist = func()

10000 loops, best of 3: 60.5 µs per loop

How can these tests be explained ?

codegeek
  • 32,236
  • 12
  • 63
  • 63
  • 8
    Defining/calling the function may slow things down more than the local variables speed things up. –  Nov 19 '13 at 15:13
  • 4
    Indeed, try to limit the difference between code fragments to a single change. Consider defining a function that uses a local variable, and a function that uses a global variable. Then call both and time the results. – Dennis Jaheruddin Nov 19 '13 at 15:15
  • The question is not about speed in general, but about local VS global. – Alexander Stavonin Nov 19 '13 at 15:15
  • 4
    He's suggesting your test isn't sufficiently isolating the variables to just local vs global, so it's not a valid experiment. Essentially, your asking, "if A is supposed to be slower than B, why is A + C faster than B + D, ignoring C and D?" He's saying C and D can't be ignored. – Silas Ray Nov 19 '13 at 15:17
  • 2
    Yeah, it's about local vs. global but you are making a test "global" vs. "local + defining a function + calling a function" – Alfe Nov 19 '13 at 15:22
  • 3
    @AlexanderStavonin: the fact that the "tests" were taken from wiki.python.org/moin/PythonSpeed/PerformanceTips doesn't make them valid _for testing global vs local access time_ - specially when they were designed to test for loops vs list comprehension vs map. – bruno desthuilliers Nov 19 '13 at 15:28
  • Except that those very examples make a point of aliasing `append` (and `upper` for that matter) and calling the aliases within the loop rather than calling them as attributes of their parents in each iteration. Those lookups could well be more costly than the local/global difference. The .2 µs variance you got isn't exactly statistically significant given the overall value is 60. – Silas Ray Nov 19 '13 at 15:29
  • 1
    Look at the [dis module](http://docs.python.org/2/library/dis.html). Read the documentation for python bytecode instructions. Realize that some of them are much faster than others. e.g. LOAD_FAST, STORE_FAST are much faster than LOAD_GLOBAL, and STORE_GLOBAL. Also CALL_FUNCTION is pretty slow. So either LOAD_GLOBAL, STORE_GLOBAL, or CALL_FUNCTION will be your bottlenecks. – Shashank Nov 19 '13 at 17:04
  • When I have a situation when I need to worry about performance over readability, I start with profiling the code to determine the potential performance impact of the change, and avoid damaging code readability unless I can realize at least half an order of magnitude improvement. – IceArdor Nov 20 '13 at 03:39
  • Using map or a list comprehension seems appropriate here, and will probably perform on the same order of magnitude as your implementations. – IceArdor Nov 20 '13 at 03:47

1 Answers1

0

In the last example you define an extra function first. If you start the timer after finding the function it should be quicker.

735Tesla
  • 3,162
  • 4
  • 34
  • 57