([Stack:['spam']], [Stack:[3.1415, 123]])
>>> y.top()
123
Timing the Improvements
The prior section’s in-place changes stack object probably runs faster than both the
original and the tuple-tree versions, but the only way to really be sure is to time the
alternative implementations.* Since this could be something we’ll want to do more than
once, let’s first define a general module for timing functions in Python. In Exam-
ple 18-6, the built-in time module provides a clock function that we can use to get the
current CPU time in floating-point seconds, and the function timer.test simply calls
a function reps times and returns the number of elapsed seconds by subtracting stop
from start times.
Example 18-6. PP4E\Dstruct\Basic\timer.py
"generic code timer tool"
def test(reps, func, args): # or best of N? see Learning Python
import time
start = time.clock() # current CPU time in float seconds
for i in range(reps): # call function reps times
func(args) # discard any return value
return time.clock() - start # stop time - start time
There are other ways to time code, including a best-of-N approach and Python’s own
timeit module, but this module suffices for our purpose here. If you’re interested in
doing better, see Learning Python, Fourth Edition, for a larger case study on this topic,
or experiment on your own.
Next, we define a test driver script which deploys the timer, in Example 18-7. It expects
three command-line arguments: the number of pushes, pops, and indexing operations
to perform (we’ll vary these arguments to test different scenarios). When run at the top
level, the script creates 200 instances of the original and optimized stack classes and
performs the specified number of operations on each stack. Pushes and pops change
the stack; indexing just accesses it.
Example 18-7. PP4E\Dstruct\Basic\stacktime.py
"compare performance of stack alternatives"
import stack2 # list-based stacks: [x]+y
import stack3 # tuple-tree stacks: (x,y)
- Because Python is so dynamic, guesses about relative performance in Python are just as likely to be wrong as
right. Moreover, their accuracy is prone to change over time. Trust me on this. I’ve made sweeping statements
about performance in other books, only to be made wrong by a later Python release that optimized some
operations more than others. Performance measurement in Python is both nontrivial and an ongoing task.
In general, code for readability first, and worry about performance later, but always gather data to support
your optimization efforts.
Implementing Stacks| 1371