深入Python3(五) 闭合与生成器

0.摘要

  在本章中,将开始学习返回其它函数的函数、高级正则表达式和生成器。

1.我知道,让我们用正则表达式!

  如果在讲英语的国家长大,或在正规的学校学习过英语,您可能对下面的基本规则很熟悉 :

  • 如果某个单词以 S 、X 或 Z 结尾,添加 ES 。Bass 变成 basses, fax 变成 faxes,而 waltz 变成 waltzes。
  • 如果某个单词以发音的 H 结尾,加 ES;如果以不发音的 H 结尾,只需加上 S 。什么是发音的 H ?指的是它和其它字母组合在一起发出能够听到的声音。因此 coach 变成 coaches 而 rash 变成 rashes,因为在说这两个单词的时候,能够听到 CH 和 SH 的发音。但是 cheetah 变成 cheetahs,因为 H 不发音。
  • 如果某个单词以发 I 音的字母 Y 结尾,将 Y 改成 IES;如果 Y 与某个元音字母组合发其它音的话,只需加上 S 。因此 vacancy 变成 vacancies,但 day 变成 days 。
  • 如果所有这些规则都不适用,只需加上 S 并作最好的打算。

  让我们设计一个 Python 类库用来自动进行英语名词的复数形式转换。我们将以这四条规则为起点,但要记住的不可避免地还要增加更多规则。
在这里插入图片描述

  这是一条正则表达式,但它使用了在 《正则表达式》 一章中没有讲过的语法。中括号表示“匹配这些字符的其中之一”。因此 [ s x z ] [sxz] [sxz] 的意思是: “s、 x 或 z”,但只匹配其中之一。 r e . s u b ( ) re.sub() re.sub()函数执行基于正则表达式的字符串替换。
在这里插入图片描述

  通过最后一个例子,我们可以发现 r e . s u b re.sub re.sub替换所有的匹配项,而不仅仅是第一个匹配项。因此该正则表达式将 c a p s caps caps转换为 o o p s oops oops,因为无论是 c c c还是 a a a均被转换为 o o o
在这里插入图片描述

  此处将字符串的结尾(通过 $ 匹配)替换为字符串 e s es es。换句话来说,向字符串尾部添加一个 e s es es 。可以通过字符串连接来完成同样的变化,例如 n o u n + ′ e s ′ noun + 'es' noun+es,但我对每条规则都选用正则表达式,其原因将在本章稍后更加清晰。
  仔细看看,这里出现了新的变化。作为方括号中的第一个字符, ^ 有特别的含义:非。[^abc]的意思是:除了 a、 b 或 c 之外的任何字符。因此 [^aeioudgkprt] 的意思是除了 a、 e、 i、 o、 u、 d、 g、 k、 p、r 或 t 之外的任何字符。然后该字符必须紧随一个 h,其后是字符串的结尾。所匹配的是以 H 结尾且 H 发音的单词。
  此处有同样的模式:匹配以 Y 结尾的单词,而 Y 之前的字符 不是 a、 e、 i、 o 或 u。所匹配的是以 Y 结尾,且 Y 发音听起来像 I 的单词。
在这里插入图片描述
在这里插入图片描述

  最后一个例子使用了记忆分组,该分组用于保存字母 y 之前的字符。然后在替换字符串中,用到了新的语法: \1,它表示“嘿,记住的第一个分组呢?把它放到这里。”在此例中, 记住了 y 之前的 c ,在进行替换时,将用 c 替代 c,用 ies 替代 y(如果有超过一个的记忆分组,可以使用 \2 和 \3 等等)。

2.函数列表

  现在要增加一些抽象层次的内容。
在这里插入图片描述
在这里插入图片描述

  现在,每条匹配规则都有自己的函数,它们返回对 r e . s e a r c h ( ) re.search() re.search()函数调用结果;每条应用规则也都有自己的函数,它们调用 r e . s u b ( ) re.sub() re.sub()函数以应用恰当的复数变化规则。
  由于所有的规则被分割成单独的数据结构,新的 p l u r a l ( ) plural() plural()函数可以减少到几行代码。
  该技术能够成功运作的原因是 P y t h o n Python Python中一切都是对象,包括了函数。数据结构 r u l e s rules rules包含了函数——不是函数的名称,而是实际的函数对象。在 f o r for for循环中被赋值后, m a t c h e s _ r u l e matches\_rule matches_rule a p p l y _ r u l e apply\_rule apply_rule是可实际调用的函数。在第一次 f o r for for循环的迭代过程中,这相当于调用 m a t c h e s _ s x z ( n o u n ) matches\_sxz(noun) matches_sxz(noun),如果返回一个匹配值,将调用 a p p l y _ s x z ( n o u n ) apply\_sxz(noun) apply_sxz(noun)
  如果这种附加抽象层令你迷惑,可以试着展开函数以了解其等价形式。整个 f o r for for循环等价于下列代码:
在这里插入图片描述

  这段代码的好处是 plural() 函数被简化了。它处理一系列其它地方定义的规则,并以通用的方式对它们进行迭代。
在这里插入图片描述

  现在,新增的抽象层是否值得呢?嗯,还没有。让我们考虑下要向函数中新增一条规则时该如何操作。在第一例中,将需要新增一条 i f if if语句到 p l u r a l ( ) plural() plural()函数中。在第二例中,将需要新增两个函数, m a t c h _ f o o ( ) match\_foo() match_foo() a p p l y _ f o o ( ) apply\_foo() apply_foo(),然后更新 r u l e s rules rules序列以指定新的匹配和应用函数按照其它规则按顺序调用。
  但是对于下一节来说,这只是一个跳板而已,让我们继续……

3.匹配模式列表

  其实并不是真的有必要为每个匹配和应用规则定义各自的命名函数。它们从未直接被调用,而只是被添加到 r u l e s rules rules序列并从该处被调用。此外,每个函数遵循两种模式的其中之一。所有的匹配函数调用 r e . s e a r c h ( ) re.search() r

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值