Functional schmunctional...

bearophileHUGS at lycos.com bearophileHUGS at lycos.com
Tue Feb 10 16:52:11 EST 2009


Here a small benchmark:

def ip2inet01(a): # can't be used with 6
    li = a.split('.')
    assert len(li) == 4
    a = int(li[0])*16777216
    b = int(li[1])*65536
    c = int(li[2])*256
    d = int(li[3])
    return a+b+c+d

from itertools import count

def ip2inet02(a):
    blocks = a.split('.')
    assert len(blocks) in (4, 6)
    return sum(map(lambda (i, n): int(i) * 256**n, zip(reversed
(blocks), count(0))))

def ip2inet03(iptxt):
    bytes = map(int, iptxt.strip().split("."))[::-1]
    assert len(bytes) in (4, 6)
    return sum(by * 256**po for po, by in enumerate(bytes))

def ip2inet04(iptxt):
    bytes = map(int, reversed(iptxt.strip().split(".")))
    assert len(bytes) in (4, 6)
    powers256 = [1, 256, 65536, 16777216, 4294967296, 1099511627776]
    return sum(by * powers256[po] for po, by in enumerate(bytes))

def ip2inet05(iptxt):
    bytes = (int(by) for by in reversed(iptxt.strip().split(".")))
    parts = [by * ip2inet05.powers256[po] for po, by in enumerate
(bytes)]
    assert len(parts) in (4, 6)
    return sum(parts)
ip2inet05.powers256 = [1, 256, 65536, 16777216, 4294967296,
1099511627776]

def ip2inet06(a):
    li = a.split('.')
    n = len(li)
    assert n == 4 or n == 6
    if n == 4:
        return (int(li[0]) * 16777216 +
                 int(li[1]) * 65536 +
                 int(li[2]) * 256 +
                 int(li[3]))
    else:
        return (int(li[0]) * 1099511627776 +
                 int(li[1]) * 4294967296 +
                 int(li[2]) * 16777216 +
                 int(li[3]) * 65536 +
                 int(li[4]) * 256 +
                 int(li[5]))

def ip2inet07(iptxt):
    bytes = map(int, iptxt.strip().split("."))[::-1]
    assert len(bytes) in (4, 6)
    return sum(by * ip2inet07.pows[po] for po, by in enumerate(bytes))
ip2inet07.pows = [1, 256, 65536, 16777216, 4294967296, 1099511627776]

from struct import pack
def ip2inet08(n): # error
  xs = pack('L', n)
  return '.'.join(str(ord(x)) for x in xs)

def ip2inet09(iptxt): # short and readable
    bytes = map(int, iptxt.strip().split("."))[::-1]
    assert len(bytes) in (4, 6)
    return sum(by << (8*po) for po, by in enumerate(bytes))

def ip2inet10(iptxt):
    count = 0
    result = 0
    for byte in iptxt.strip().split("."):
        result <<= 8
        result += int(byte)
        count += 1
    assert count in (4, 6)
    return result

def ip2inet11(iptxt):
    bytes = iptxt.strip().split(".")
    assert len(bytes) in (4, 6)
    result = 0
    for byte in bytes:
        result <<= 8
        result += int(byte)
    return result

def ip2inet12(iptxt):
    bytes = iptxt.strip().split(".")
    assert len(bytes) in (4, 6)
    result = 0
    for byte in bytes:
        result = (result << 8) + int(byte)
    return result

def ip2inet13(a): # fastest and readable
    li = a.split('.')
    n = len(li)
    assert n == 4 or n == 6
    if n == 4:
        return ((int(li[0]) << 24) +
                 (int(li[1]) << 16) +
                 (int(li[2]) << 8) +
                 int(li[3]))
    else:
        return ((int(li[0]) << 40) +
                 (int(li[1]) << 32) +
                 (int(li[2]) << 24) +
                 (int(li[3]) << 16) +
                 (int(li[4]) << 8) +
                 int(li[5]))



def main():
    from timeit import default_timer as clock

    ip4 = "155.16.187.87"
    ip6 = "7.155.16.187.87.255"
    algos = [ip2inet02, ip2inet03, ip2inet04, ip2inet05, ip2inet06,
             ip2inet07, ip2inet09, ip2inet10, ip2inet11, ip2inet12,
             ip2inet13]
    for algo in algos:
        assert algo(ip4) == 2601565015 and algo(ip6) == 8362582038527
        t0 = clock()
        for i in xrange(10000):
            algo(ip4)
            algo(ip6)
        print algo.__name__, round(clock() - t0, 2), "s"

    import psyco; psyco.full()
    print "With Psyco:"
    for algo in algos:
        t0 = clock()
        for i in xrange(10000):
            algo(ip4)
            algo(ip6)
        print algo.__name__, round(clock() - t0, 2), "s"


main()

ip2inet02 2.68 s
ip2inet03 1.79 s
ip2inet04 1.72 s
ip2inet05 1.88 s
ip2inet06 0.98 s
ip2inet07 1.57 s
ip2inet09 1.5 s
ip2inet10 1.07 s
ip2inet11 1.07 s
ip2inet12 1.03 s
ip2inet13 0.95 s

With Psyco (indipendent run! Not normally successive):
ip2inet02 2.66 s
ip2inet03 1.66 s
ip2inet04 1.97 s
ip2inet05 1.66 s
ip2inet06 0.57 s
ip2inet07 1.5 s
ip2inet09 1.54 s
ip2inet10 0.53 s
ip2inet11 0.76 s
ip2inet12 0.52 s
ip2inet13 0.8 s

So if you need speed you the version #13 is better, if you want short
and readable code (but not too much slow) you can use #9, and if you
want code easy to understand by every one and easy to translate to
other languages then you can use #12.

Bye,
bearophile



More information about the Python-list mailing list