第 18 章 性能优化

性能优化 (Performance tuning) 是一件多姿多彩的事情。Python 是一种解释性语言并不表示你不应该担心代码优化。但也不必 担心。

18.1. 概览

由于代码优化过程中存在太多的不明确因素,以至于你很难清楚该从何入手。

让我们从这里开始:你真的确信你要这样做吗? 你的代码真的那么差吗?值得花时间去优化它吗?在你的应用程序的生命周期中,与花费在等待一个远程数据库服务器,或是等待用户输入相比,运行这段代码将花费多少时间?

第二,你确信已经完成代码编写了吗? 过早的优化就像是在一块半生不熟的蛋糕上撒糖霜。你花费了几小时、几天 (或更长) 时间来优化你的代码以提高性能,却发现它不能完成你希望它做的工作。那是浪费时间。

这并不是说代码优化毫无用处,但是你需要检查一下整个系统,并且确定把时间花在这上面是值得的。在优化代码上每花费一分钟,就意味着你少了增加新功能、编写文档或者陪你的孩子玩或者编写单元测试的一分钟。

哦,是的,单元测试。不必我说,在开始性能优化之前你需要一个完全的单元测试集。你最不需要的就是在乱动你的算法时引入新的问题。

谨记着这些忠告,让我们来看一些优化 Python 代码的技术。我们要研究的代码是 Soundex 算法的实现。Soundex 是一种 20 世纪在美国人口普查中归档姓氏的方法。它把听起来相似的姓氏归在一起,使得在即便错误拼写的情况下调查者仍能查找到。Soundex 今天仍然因差不多的原因被应用着,当然现在用计算机数据库服务器了。大部分的数据库服务器都有 Soundex 函数。

Soundex 算法有几个差别不大的变化版本。这是本章使用的:

  1. 名字的第一个字母不变。
  2. 根据特定的对照表,将剩下的字母转换为数字:
    • B、 F、 P 和 V 转换为 1。
    • C、 G、 J、 K、 Q、 S、 X 和 Z 转换为 2。
    • D 和 T 转换为 3。
    • L 转换为 4。
    • M 和 N 转换为 5。
    • R 转换为 6。
    • 所有其他字母转换为 9。
  3. 去除连续重复。
  4. 去除所有 9。
  5. 如果结果都少于四个字符 (第一个字母加上后面的三位字符),就以零补齐。
  6. 如果结果超过四个字符,丢弃掉四位之后的字符。

比如,我的名字 Pilgrim 被转换为 P942695。没有连续重复,所以这一步不需要做。然后是去除 9,剩下 P4265。太长了,所以你把超出的字符丢弃,剩下 P426。

另一个例子:Woo 被转换为 W99,变成 W9,变成 W,然后以补零成为 W000。

这是 Soundex 函数的第一次尝试:

例 18.1. soundex/stage1/soundex1a.py

如果您还没有下载本书附带的样例程序, 可以 下载本程序和其他样例程序


import string, re

charToSoundex = {"A": "9",
                 "B": "1",
                 "C": "2",
                 "D": "3",
                 "E": "9",
                 "F": "1",
                 "G": "2",
                 "H": "9",
                 "I": "9",
                 "J": "2",
                 "K": "2",
                 "L": "4",
                 "M": "5",
                 "N": "5",
                 "O": "9",
                 "P": "1",
                 "Q": "2",
                 "R": "6",
                 "S": "2",
                 "T": "3",
                 "U": "9",
                 "V": "1",
                 "W": "9",
                 "X": "2",
                 "Y": "9",
                 "Z": "2"}

def soundex(source):
    "convert string to Soundex equivalent"

    # Soundex requirements:
    # source string must be at least 1 character
    # and must consist entirely of letters
    allChars = string.uppercase + string.lowercase
    if not re.search('^[%s]+$' % allChars, source):
        return "0000"

    # Soundex algorithm:
    # 1. make first character uppercase
    source = source[0].upper() + source[1:]
    
    # 2. translate all other characters to Soundex digits
    digits = source[0]
    for s in source[1:]:
        s = s.upper()
        digits += charToSoundex[s]

    # 3. remove consecutive duplicates
    digits2 = digits[0]
    for d in digits[1:]:
        if digits2[-1] != d:
            digits2 += d
        
    # 4. remove all "9"s
    digits3 = re.sub('9', '', digits2)
    
    # 5. pad end with "0"s to 4 characters
    while len(digits3) < 4:
        digits3 += "0"
        
    # 6. return first 4 characters
    return digits3[:4]

if __name__ == '__main__':
    from timeit import Timer
    names = ('Woo', 'Pilgrim', 'Flingjingwaller')
    for name in names:
        statement = "soundex('%s')" % name
        t = Timer(statement, "from __main__ import soundex")
        print name.ljust(15), soundex(name), min(t.repeat())

进一步阅读

任天堂官网登录平台 凤凰时时彩平台 时时彩后三组选经验 玩时时彩能赚钱吗 时时彩自动投注软件有用吗
时时彩卡盟 时时彩代理会被通缉吗 老时时彩口碑平台 时时彩后二49注万能码 合乐时时彩平台登陆
英皇娱乐时时彩的网站 外卖平台靠什么赚钱 时时彩计划微信群发 时时彩手机平台哪个好 时时彩送彩金平台
时时彩网赚项目 时时彩娱乐平台注册 时时彩代理赚返点怎么算 时时彩后三杀一码包中 澳门时时彩手机版
七乐彩155开奖号码 旺旺时时彩破解 福利彩票开奖结果 河南11选5杀号 极速赛车电影余男
时时彩开奖软件 陕西十一选五摇奖 福彩3d乐彩论坛 福建快3开奖号码表 2017年3d焰舞字谜汇总
上海时时乐出号走势图 广西体彩11选5开奖查询 上海天天彩选四彩票控 新疆时时彩开奖号码查询结果 甘肃十一选五走势图解★?计划?
幸运28玩法 广西11选5号码分布图 五分彩开奖皇恩娱乐 时时彩开奖 吉林十一选五75期开奖结果