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_sxz,而 applyRule 将获得 apply_sxz。在第二次迭代中(假设您能走到那一步),matchesRule 将被赋值为 match_h,而 applyRule 将被赋值为 apply_h
3 请记住,Python 中的一切都是对象,包括函数。rules 包含实际的函数;不是函数的名称,而是实际的函数。当它们在 for 循环中被赋值时,matchesRuleapplyRule 就是您可以调用的实际函数。所以在 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 列表,以指定新的匹配和应用函数相对于其他规则应该在哪个位置调用。

这实际上只是下一节的垫脚石。让我们继续。