isFloat: Without Exception-Handling

Mark McEahern marklists at mceahern.com
Fri Sep 20 12:32:19 EDT 2002


For what it's worth, here's a slightly tweaked version of the test harness.
It shuffles the function list before testing and does multiple test runs and
then averages the results.  I'm posting this mainly so that I can archive
this on this list without having to bother figuring out where to put it on
my own hard disk.  <wink>

isFloatExcept comes out pretty consistently almost twice as fast as the
RE-based approach.  Now, wouldn't I feel real dumb to find Python comes with
a builtin isfloat?

If not, are there other alternatives for doing this?

Easy come, easy go.

Cheers,

// m

#!/usr/bin/env python

import re
import random
import operator
from time import clock

# Compile up front.
floatPattern = re.compile(r"^[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?$")

def isFloatExcept(s):
    try:
        float(s)
        return True
    except (ValueError, TypeError), e:
        return False

def isFloatRE(s):
    floatRE = r"^[-+]?(\d+\.?\d*|\.\d+)([eE][-+]?\d+)?$"
    return re.match(floatRE, str(s)) is not None

def isFloatRECompiled(s):
    return floatPattern.match(str(s)) is not None

def time_it(fn, test_data, n):
    time_in = clock()
    for x in xrange(n):
        for (s, expected) in test_data:
            actual = fn(s)
            assert actual == expected
    time_out = clock()
    return time_out - time_in

def show(fn, r, fastest):
    avg = average(r)
    ratio = (avg / fastest) * 100
    print "%-20s  %1.3f  %2.f" % (fn.func_name, average(r), ratio)

def average(seq):
    return reduce(operator.add, seq) / len(seq)

def test():
    test_data = [(1.2, True),
                 (1, True),
                 (-1, True),
                 (1e+10, True),
                 ("1e-10", True),
                 ("banana", False),
                 ("5j", False),
                 (4+0j, False),
                 (isFloatExcept, False),
                 (__import__, False),
                 (clock, False)]
    test_runs = 10
    n = 100
    results = {}
    functions = [isFloatExcept, isFloatRE, isFloatRECompiled]
    for t in xrange(test_runs):
        random.shuffle(functions)
        for fn in functions:
            r = time_it(fn, test_data, n)
            results.setdefault(fn, [])
            results[fn].append(r)

    keys = results.keys()
    keys.sort(lambda x, y: cmp(average(results[x]), average(results[y])))
    fastest = average(results[keys[0]])
    print "%-20s  %s  %s" % ("name", "clock", "cmp")
    for fn in keys:
        show(fn, results[fn], fastest)

if __name__ == "__main__":
    test()
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: junk.py
URL: <http://mail.python.org/pipermail/python-list/attachments/20020920/9617ca91/attachment.ksh>


More information about the Python-list mailing list