17.5. plural.py, 第 4 阶段

让我们精炼出代码中的重复之处,以便更容易地定义新规则。

例 17.9. plural4.py


import re

def buildMatchAndApplyFunctions((pattern, search, replace)):  
    matchFunction = lambda word: re.search(pattern, word)      
    applyFunction = lambda word: re.sub(search, replace, word) 
    return (matchFunction, applyFunction)                      
buildMatchAndApplyFunctions 是一个动态生成其它函数的函数。它将 patternsearchreplace (实际上是一个元组,我们很快就会提到这一点),通过使用 lambda 语法构建一个接受单参数 (word) 并以传递给 buildMatchAndApplyFunctionspattern 和传递给新函数的 word 调用 re.search 的匹配函数!哇塞!
构建应用规则函数的方法相同。应用规则函数是一个接受单参数并以传递给 buildMatchAndApplyFunctionssearchreplace 以及传递给这个应用规则函数的 word 调用 re.sub 的函数。在一个动态函数中应用外部参数值的技术被称作闭合 (closures)。你实际上是在应用规则函数中定义常量:它只接受一个参数 (word),但用到了定义时设置的两个值 (searchreplace)。
最终,时时彩计划软件公式:buildMatchAndApplyFunctions 函数返回一个包含两个值的元组:你刚刚创建的两个函数。你在这些函数中定义的常量 (matchFunction 中的 pattern 以及 applyFunction 中的 searchreplace) 保留在这些函数中,由 buildMatchAndApplyFunctions 一同返回。这简直太酷了。

如果这太费解 (它应该是这样,这是个怪异的东西),可能需要通过了解它的使用来搞明白。

例 17.10. plural4.py 继续

patterns = \
  (
    ('[sxz]$', '$', 'es'),
    ('[^aeioudgkprt]h$', '$', 'es'),
    ('(qu|[^aeiou])y$', 'y$', 'ies'),
    ('$', '$', 's')
  )                                                 
rules = map(buildMatchAndApplyFunctions, patterns)  
我们的复数化规则现在被定义成一组字符串 (不是函数)。第一个字符串是你在调用 re.search 时使用的正则表达式;第二个和第三个字符串是你在通过调用 re.sub 来应用规则将名词变为复数时使用的搜索和替换表达式。
这很神奇。把传进去的 patterns 字符串转换为传回来的函数。如何做到的呢?将这些字符串映射给 buildMatchAndApplyFunctions 函数之后,三个字符串参数转换成了两个函数组成的元组。这意味着 rules 被转换成了前面范例中相同的内容:由许多调用 re.search 函数的匹配函数和调用 re.sub 的规则应用函数构成的函数组组成的一个元组。

我发誓这不是我信口雌黄:rules 被转换成了前面范例中相同的内容。剖析 rules 的定义,你看到的是:

例 17.11. 剖析规则定义

rules = \
  (
    (
     lambda word: re.search('[sxz]$', word),
     lambda word: re.sub('$', 'es', word)
    ),
    (
     lambda word: re.search('[^aeioudgkprt]h$', word),
     lambda word: re.sub('$', 'es', word)
    ),
    (
     lambda word: re.search('[^aeiou]y$', word),
     lambda word: re.sub('y$', 'ies', word)
    ),
    (
     lambda word: re.search('$', word),
     lambda word: re.sub('$', 's', word)
    )
   )                                          

例 17.12. plural4.py 的完成


def plural(noun):                                  
    for matchesRule, applyRule in rules:            
        if matchesRule(noun):                      
            return applyRule(noun)                 
由于 rules 列表和前面的范例是相同的,plural 函数没有变化也就不令人诧异了。记住,这没什么特别的,按照顺序调用一系列函数。不必在意规则是如何定义的。在第 2 阶段,它们被定义为各具名称的函数。在第 3 阶段,他们被定义为匿名的 lambda 函数。现在第 4 阶段,它们通过 buildMatchAndApplyFunctions 映射原始的字符串列表被动态创建。无所谓,plural 函数的工作方法没有变。

还不够兴奋吧!我必须承认,在定义 buildMatchAndApplyFunctions 时我跳过了一个微妙之处。让我们回过头再看一下。

例 17.13. 回头看 buildMatchAndApplyFunctions


def buildMatchAndApplyFunctions((pattern, search, replace)):   
注意到双括号了吗?这个函数并不是真的接受三个参数,实际上只接受一个参数:一个三元素元组。但是在函数被调用时元组被展开了,元组的三个元素也被赋予了不同的变量:pattern, searchreplace。乱吗?让我们在使用中理解。

例 17.14. 调用函数时展开元组

>>> def foo((a, b, c)):
...     print c
...     print b
...     print a
>>> parameters = ('apple', 'bear', 'catnap')
>>> foo(parameters) 
catnap
bear
apple
调用 foo 的正确方法是使用一个三元素元组。函数被调用时,元素被分别赋予 foo 中的多个局部变量。

现在,让我们回过头看一看这个元组自动展开技巧的必要性。patterns 是一个元组列表,并且每个元组都有三个元素。调用 map(buildMatchAndApplyFunctions, patterns),这并 意味着是以三个参数调用 buildMatchAndApplyFunctions。使用 map 映射一个列表到函数时,通常使用单参数:列表中的每个元素。就 patterns 而言,列表的每个元素都是一个元组,所以 buildMatchAndApplyFunctions 总是是以元组来调用,在 buildMatchAndApplyFunctions 中使用元组自动展开技巧将元素赋值给可以被使用的变量。

时时彩计划王者团队 哪个彩票平台返水多 内蒙古时时彩快三开奖结果走势图 彩票大赢家软件下载 易算时时彩完美破解版
求重庆时时彩软件计划 时时彩注册送38元彩金 时时彩开户送体验金 重庆时时彩选胆图表 5年以上的时时彩平台
趋势为王时时彩软件 小a时时彩自动投注 时时彩娱乐平台 重庆时时彩软件大富翁 内蒙古时时彩开奖预测
合乐时时彩平台注册 江西时时彩出事了 时时彩返点最高的平台 重庆时时彩中3走势图 苹果手机时时彩软件
排列五杀号定胆 澳门官方 广州快乐十分玩法 时时彩平台哪个好 德州扑克小游戏
幸运28模式 福建11选5开奖结杲 云南快乐十分走势图基本走势图 偷天txt全集下载 北京pk拾走势图
百家乐怎么开户 云南十一选五走势图 极速赛车彩票开奖 辽宁35选7走势图表 七乐彩开奖时间
北京赛车pk10 青海11选5遗漏 秒速赛车直播 福建22选5 彩票双色球必中预测