17.3. plural.py, 第 2 阶段

现在你将增加一个抽象过程。你从定义一个规则列表开始:如果这样,就做那个,否则判断下一规则。让我们暂时将程序一部分复杂化以便使另一部分简单化。

例 17.6. plural2.py


import re

def match_sxz(noun):                          
    return re.search('[sxz]$', noun)          

def apply_sxz(noun):                          
    return re.sub('$', 'es', noun)            

def match_h(noun):                            
    return re.search('[^aeioudgkprt]h$', noun)

def apply_h(noun):                            
    return re.sub('$', 'es', noun)            

def match_y(noun):                            
    return re.search('[^aeiou]y$', noun)      
        
def apply_y(noun):                            
    return re.sub('y$', 'ies', noun)          

def match_default(noun):                      
    return 1                                  
        
def apply_default(noun):                      
    return noun + 's'                         

rules = ((match_sxz, apply_sxz),
         (match_h, apply_h),
         (match_y, apply_y),
         (match_default, apply_default)
         )                                     1

def plural(noun):                             
    for matchesRule, applyRule in rules:       2
        if matchesRule(noun):                  3
            return applyRule(noun)             4
1 这个版本看起来更加复杂 (至少是长了),但做的工作没有变化:试图顺序匹配四种不同规则,并在匹配时应用恰当的正则表达式。不同之处在于,每个独立的匹配和应用规则都在自己的函数中定义,并且这些函数列于 rules 变量这个元组的元组之中。
2 使用一个 for 循环,你可以根据 rules 元组一次性进行匹配和应用规则两项工作 (一个匹配和一个应用)。for 循环第一轮中,matchesRule 将使用 match_sxzapplyRule 将使用 apply_sxz;在第二轮中 (假设真走到了这么远),matchesRule 将被赋予 match_happlyRule 将被赋予 apply_h
3 记住 Python 中的一切都是对象,包括函数。rules 包含函数;不是指函数名,而是指函数本身。当 matchesRuleapplyRulefor 循环中被赋值后,它们就成了你可以调用的真正函数。因此,在 for 循环第一轮中,这就相当于调用 matches_sxz(noun)
4 for 循环第一轮中,这就相当于调用 apply_sxz(noun),等等。

这个抽象过程有些令人迷惑,试着剖析函数看看实际的等价内容。这个 for 循环相当于:

例 17.7. 剖析 plural 函数


def plural(noun):
    if match_sxz(noun):
        return apply_sxz(noun)
    if match_h(noun):
        return apply_h(noun)
    if match_y(noun):
        return apply_y(noun)
    if match_default(noun):
        return apply_default(noun)

这里的好处在于 plural 函数现在被简化了。它以普通的方法反复使用其它地方定义的规则。获得一个匹配规则,匹配吗?调用并应用规则。规则可以在任意地方以任意方法定义,plural 函数对此并不关心。

现在,添加这个抽象过程值得吗?嗯……还不值。让我们看看如何向函数添加一个新的规则。啊哈,在先前的范例中,需要向 plural 函数添加一个 if 语句;在这个例子中,需要增加两个函数:match_fooapply_foo,然后更新 rules 列表指定在什么相对位置调用这个新匹配和新规则应用。

这其实不过是步入下一节的一个基石。让我们继续。