Learning Python - Mark Lutz [592]
prime(13); prime(13.0)
prime(15); prime(15.0)
prime(3); prime(2)
prime(1); prime(-3)
Here is the module in action; the // operator allows it to work for floating-point numbers too, even though it perhaps should not:% python primes.py
13 is prime
13.0 is prime
15 has factor 5
15.0 has factor 5.0
3 is prime
2 is prime
1 not prime
-3 not prime
This function still isn’t very reusable—it could return values, instead of printing—but it’s enough to run experiments. It’s also not a strict mathematical prime (floating points work), and it’s still inefficient. Improvements are left as exercises for more mathematically minded readers. (Hint: a for loop over range(y, 1, −1) may be a bit quicker than the while, but the algorithm is the real bottleneck here.) To time alternatives, use the built-in time module and coding patterns like those used in this general function-call timer (see the library manual for details):def timer(reps, func, *args):
import time
start = time.clock()
for i in range(reps):
func(*args)
return time.clock() - start
List comprehensions. Here is the sort of code you should write; I may have a preference, but I’m not telling:>>> values = [2, 4, 9, 16, 25]
>>> import math
>>> res = []
>>> for x in values: res.append(math.sqrt(x))
...
>>> res
[1.4142135623730951, 2.0, 3.0, 4.0, 5.0]
>>> list(map(math.sqrt, values))
[1.4142135623730951, 2.0, 3.0, 4.0, 5.0]
>>> [math.sqrt(x) for x in values]
[1.4142135623730951, 2.0, 3.0, 4.0, 5.0]
Timing tools. Here is some code I wrote to time the three square root options, along with the results in 2.6 and 3.0. The last result of each function is printed to verify that all three do the same work:# File mytimer.py (2.6 and 3.0)
...same as listed in Chapter 20...
# File timesqrt.py
import sys, mytimer
reps = 10000
repslist = range(reps) # Pull out range list time for 2.6
from math import sqrt # Not math.sqrt: adds attr fetch time
def mathMod():
for i in repslist:
res = sqrt(i)
return res
def powCall():
for i in repslist:
res = pow(i, .5)
return res
def powExpr():
for i in repslist:
res = i ** .5
return res
print(sys.version)
for tester in (mytimer.timer, mytimer.best):
print('<%s>' % tester.__name__)
for test in (mathMod, powCall, powExpr):
elapsed, result = tester(test)
print ('-'*35)
print ('%s: %.5f => %s' %
(test.__name__, elapsed, result))
Following are the test results for Python 3.0 and 2.6. For both, it looks like the math module is quicker than the ** expression, which is quicker than the pow call; however, you should try this with your code and on your own machine and version of Python. Also, note that Python 3.0 is nearly twice as slow as 2.6 on this test; 3.1 or later might perform better (time this in the future to see for yourself):c:\misc> c:\python30\python timesqrt.py
3.0.1 (r301:69561, Feb 13 2009, 20:04:18) [MSC v.1500 32 bit (Intel)]
----------------------------------- mathMod: 5.33906 => 99.994999875 ----------------------------------- powCall: 7.29689 => 99.994999875 ----------------------------------- powExpr: 5.95770 => 99.994999875 ----------------------------------- mathMod: 0.00497 => 99.994999875 ----------------------------------- powCall: 0.00671 => 99.994999875 ----------------------------------- powExpr: 0.00540 => 99.994999875 c:\misc> c:\python26\python timesqrt.py 2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)] ----------------------------------- mathMod: 2.61226 => 99.994999875 ----------------------------------- powCall: 4.33705 => 99.994999875 ----------------------------------- powExpr: 3.12502 => 99.994999875 ----------------------------------- mathMod: 0.00236 => 99.994999875 ----------------------------------- powCall: 0.00402 => 99.994999875 ----------------------------------- powExpr: 0.00287 => 99.994999875 To time the relative speeds of Python 3.0 dictionary comprehensions and equivalent for loops interactively, run a session like the following. It appears