Online Book Reader

Home Category

Learning Python - Mark Lutz [284]

By Root 1668 0
operation on each iteration, such as addition, instead of calling a trivial built-in function like abs (the omitted parts of the following are the same as before):

# File timeseqs.py

...

...

def forLoop():

res = []

for x in repslist:

res.append(x + 10)

return res

def listComp():

return [x + 10 for x in repslist]

def mapCall():

return list(map((lambda x: x + 10), repslist)) # list in 3.0 only

def genExpr():

return list(x + 10 for x in repslist) # list in 2.6 + 3.0

def genFunc():

def gen():

for x in repslist:

yield x + 10

return list(gen())

...

...

Now the need to call a user-defined function for the map call makes it slower than the for loop statements, despite the fact that the looping statements version is larger in terms of code. On Python 3.0:

C:\misc> c:\python30\python timeseqs.py

3.0.1 (r301:69561, Feb 13 2009, 20:04:18) [MSC v.1500 32 bit (Intel)]

---------------------------------

forLoop : 2.60754 => [10...10009]

---------------------------------

listComp : 1.57585 => [10...10009]

---------------------------------

mapCall : 3.10276 => [10...10009]

---------------------------------

genExpr : 1.96482 => [10...10009]

---------------------------------

genFunc : 1.95340 => [10...10009]

The Python 2.5 results on a slower machine were again relatively similar in the prior edition, but twice as slow due to test machine differences:

2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)]

forStatement => 5.25699996948

listComprehension => 2.68400001526

mapFunction => 5.96900010109

generatorExpression => 3.37400007248

Because the interpreter optimizes so much internally, performance analysis of Python code like this is a very tricky affair. It’s virtually impossible to guess which method will perform the best—the best you can do is time your own code, on your computer, with your version of Python. In this case, all we should say for certain is that on this Python, using a user-defined function in map calls can slow performance by at least a factor of 2, and that list comprehensions run quickest for this test.

As I’ve mentioned before, however, performance should not be your primary concern when writing Python code—the first thing you should do to optimize Python code is to not optimize Python code! Write for readability and simplicity first, then optimize later, if and only if needed. It could very well be that any of the five alternatives is quick enough for the data sets your program needs to process; if so, program clarity should be the chief goal.

Timing Module Alternatives

The timing module of the prior section works, but it’s a bit primitive on multiple fronts:

It always uses the time.clock call to time code. While that option is best on Windows, the time.time call may provide better resolution on some Unix platforms.

Adjusting the number of repetitions requires changing module-level globals—a less than ideal arrangement if the timer function is being used and shared by multiple importers.

As is, the timer works by running the test function a large number of times. To account for random system load fluctuations, it might be better to select the best time among all the tests, instead of the total time.

The following alternative implements a more sophisticated timer module that addresses all three points by selecting a timer call based on platform, allowing the repeat count to be passed in as a keyword argument named _reps, and providing a best-of-N alternative timing function:

# File mytimer.py (2.6 and 3.0)

"""

timer(spam, 1, 2, a=3, b=4, _reps=1000) calls and times spam(1, 2, a=3)

_reps times, and returns total time for all runs, with final result;

best(spam, 1, 2, a=3, b=4, _reps=50) runs best-of-N timer to filter out

any system load variation, and returns best time among _reps tests

"""

import time, sys

if sys.platform[:3] == 'win':

timefunc = time.clock # Use time.clock on Windows

else:

timefunc = time.time # Better resolution on some Unix platforms

def trace(*args): pass # Or: print args

def timer(func, *pargs,

Return Main Page Previous Page Next Page

®Online Book Reader