Hassan Baig Hassan Baig - 1 month ago 11
Python Question

Python timeit function crashing with NameError: global name does not exist

I'm trying to benchmark two comparable statements in python2.7.

One statement prints a list of numbers retrieved from memory. The other statement prints a list of the same numbers retrieved from a redis list maintained on the same server.

E.g.

pylist1 = [1,2,3,4,5]
pylist2 = my_server.lrange("nums:5",0,-1) #where nums:5 = [1,2,3,4,5]


How do I use timeit to benchmark
print pylist1
and
print pylist2
?

I'm trying the following in the python shell:

import timeit
import redis
POOL = redis.ConnectionPool(host='127.0.0.1',port=6379,db=0)
my_server = redis.Redis(connection_pool=POOL)
pylist1 = [1,2,3,4,5]
pylist2 = my_server.lrange("nums:5",0,-1)
print min(timeit.Timer('print pylist1').repeat(7,1000))


This just crashes with
NameError: global name 'pylist1' does not exist
. That's weird because
print pylist1
works perfectly !? Need help in doing what I intend to do correctly.

Answer

The documentation for Timer says:

Class for timing execution speed of small code snippets.

The constructor takes a statement to be timed, an additional statement used for setup, and a timer function. Both statements default to 'pass'; the timer function is platform-dependent (see module doc string). If 'globals' is specified, the code will be executed within that namespace (as opposed to inside timeit's namespace).

[...]

This tells you that the statement executed by the Timer is, by default, executed in its own namespace which does not have access to the outer namespaces nor it modifies them. To change this you can use the setup statement to import the names you need:

Timer(..., setup='from __main__ import pylist1')

Or just specify to use the current namespace to execute the code:

Timer(..., globals=globals())

Note that if the statement you are timing modifies the variables they will actually change in the module. It may be better to use a copy of the globals instead:

Timer(...., globals=globals().copy())

# even better

import copy
Timer(..., globals={'pylist1': copy.deepcopy(pylist1))

In this the code that is being profiled will not modify your global variables

Comments