🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 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) ) def plural(noun): for matchesRule, applyRule in rules: if matchesRule(noun): return applyRule(noun) ``` | | | | --- | --- | | \[1\] | 这个版本看起来更加复杂 (至少是长了),但做的工作没有变化:试图顺序匹配四种不同规则,并在匹配时应用恰当的正则表达式。不同之处在于,每个独立的匹配和应用规则都在自己的函数中定义,并且这些函数列于 `rules` 变量这个元组的元组之中。 | | \[2\] | 使用一个 `for` 循环,你可以根据 `rules` 元组一次性进行匹配和应用规则两项工作 (一个匹配和一个应用)。`for` 循环第一轮中,`matchesRule` 将使用 `match_sxz`,`applyRule` 将使用 `apply_sxz`;在第二轮中 (假设真走到了这么远),`matchesRule` 将被赋予 `match_h`,`applyRule` 将被赋予 `apply_h`。 | | \[3\] | 记住 [Python 中的一切都是对象](../getting_to_know_python/everything_is_an_object.html "2.4. 万物皆对象"),包括函数。`rules` 包含函数;不是指函数名,而是指函数本身。当 `matchesRule` 和 `applyRule` 在 `for` 循环中被赋值后,它们就成了你可以调用的真正函数。因此,在 `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_foo` 和 `apply_foo`,然后更新 `rules` 列表指定在什么相对位置调用这个新匹配和新规则应用。 这其实不过是步入下一节的一个基石。让我们继续。