楼主: lastwinner

[参考文档] Python 研究(Dive Into Python)

[复制链接]
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
321#
 楼主| 发表于 2006-7-19 00:56 | 只看该作者
16.8. 小结
regression.py 程序及其输出到现在应该很清楚了。

你现在应该能够很自如地做到如下事情:

从命令行操作 路径信息。
在不使用列表遍历的情况下, 使用 filter 过滤列表。
在不使用列表遍历的情况下, 使用 map关联列表。
动态导入模块。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
322#
 楼主| 发表于 2006-7-19 00:57 | 只看该作者
第 17 章 动态函数
17.1. 概览
17.2. plural.py, 第 1 阶段
17.3. plural.py, 第 2 阶段
17.4. plural.py, 第 3 阶段
17.5. plural.py, 第 4 阶段
17.6. plural.py, 第 5 阶段
17.7. plural.py, 第 6 阶段
17.8. 小结
17.1. 概览
我想谈谈名词复数。 还有,返回其它函数的函数,高级的正则表达式和生成器(Generator)。生成器是 Python 2.3 新引入的。 但首先还是让我们先来谈谈如何生成名词复数。

如果你还没有看过 第 7 章 正则表达式,现在是个绝佳的机会。 这章中假定你已理解了正则表达式的基础内容并迅速深入更高级的应用。

英语是一个吸收很多外来语而令人疯掉的语言,把单数名词变成复数的规则则是复杂而又多变的。 有规则,有例外,更有例外的例外。

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


  • 如果一个词以 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 并祈祷不会错。


(我知道有很多例外情况, 比如: “Man” 变成 “men”, “woman” 变成 “women”,但是, “human” 却变成 “humans”。 “Mouse” 变成 “mice”, “louse” 变成 “lice”, 但是, “house” 却变成 “houses”。 “Knife” 变成 “knives”, “wife” 变成 “wives”,但是 “lowlife” 却变成 “lowlifes”。 更不要说那些复数根本就不需要变化的词了,比如 “sheep”, “deer” 和 “haiku”。)
其他的语言当然完全不同。
让我们来设计一个复数化名词的模块吧! 从英语名词开始,仅考虑上面的四种规则,但是记得你将来需要不断添加规则,更可能最后添加进更多的语言。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
323#
 楼主| 发表于 2006-7-19 00:58 | 只看该作者
17.2. plural.py, 第 1 阶段
你所针对的单词,至少在英语中是字符串和字符。 另外你需要规则来找出不同的字符(字母)组合,并对他们进行不同的操作。这听起来像是正则表达式的工作。

例 17.1. plural1.py

import re

def plural(noun):                           
    if re.search('[sxz]$', noun):            
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeioudgkprt]h$', noun):
        return re.sub('$', 'es', noun)      
    elif re.search('[^aeiou]y$', noun):      
        return re.sub('y$', 'ies', noun)     
    else:                                    
        return noun + 's'                    
  好啦,这是一个正则表达式,但是它使用了你在 第 7 章 正则表达式 中未曾见过的语法。 方括号的意思是 “完全匹配这些字符中的一个”。 也就是说,[sxz] 意味着 “s,或者 x,再或者 z”, 但只是其中的一个。 $ 应该不陌生,它意味着匹配字符串的结尾。 也就是说,检查 noun 是否以 s,x,或者 z 结尾。
  re.sub 函数起着以正则表达式为基础的替换工作。 让我们更具体地看看它。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
324#
 楼主| 发表于 2006-7-19 00:59 | 只看该作者
例 17.2. 介绍 re.sub
>>> import re
>>> re.search('[abc]', 'Mark')   
<_sre.SRE_Match object at 0x001C1FA8>
>>> re.sub('[abc]', 'o', 'Mark')
'Mork'
>>> re.sub('[abc]', 'o', 'rock')
'rook'
>>> re.sub('[abc]', 'o', 'caps')
'oops'
  Mark 包含 a, b, 或者 c吗? 是的,含有 a。
  好的,现在找出 a, b,或者 c 并以 o 取代之。 Mark 就变成 Mork 了。
  同一方法可以将 rock 变成 rook。
  你可能认为它可以将 caps 变成 oaps,但事实并非如此。 re.sub 替换 所有 的匹配项,并不只是第一个匹配项。 因此正则表达式将会把 caps 变成 oops。因为, c 和 a 都被转换为 o了。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
325#
 楼主| 发表于 2006-7-19 00:59 | 只看该作者
例 17.3. 回到 plural1.py

import re

def plural(noun):                           
    if re.search('[sxz]$', noun):            
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeioudgkprt]h$', noun):
        return re.sub('$', 'es', noun)        
    elif re.search('[^aeiou]y$', noun):      
        return re.sub('y$', 'ies', noun)     
    else:                                    
        return noun + 's'                    
  回到 plural 函数。 你在做什么? 你在以 es 取代字符串的结尾。 换句话说,追加 es 到字符串。 你可以通过字符串拼合做到相同的事。例如: noun + 'es', 但是我使用正则表达式做这一切, 既是为了保持一致,也是为了本章稍后你会明白的其它原因。
  仔细看看,这是另一个新的内容。 ^ 是方括号里面的第一个字符,这有特别的含义:否定。 [^abc] 意味着 “ 除 a、 b、 和 c 以外的 任意单字符”。 所以, [^aeioudgkprt] 意味着除 a、 e、 i、 o、 u、 d、 g、 k、 p、 r 和 t 以外的任意字符。 这个字符之后应该跟着一个 h,然后是字符串的结尾。你在寻找的是以发音的 H 结尾的单词。
  这是一个相似的表达:匹配 Y 前面不是 a、 e、 i、 o 和 u,并以这个 Y 结尾的单词。你在查找的是以发 I 音的 Y 结尾的单词。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
326#
 楼主| 发表于 2006-7-19 00:59 | 只看该作者
例 17.4. 正则表达式中否定的更多应用
>>> import re
>>> re.search('[^aeiou]y$', 'vacancy')
<_sre.SRE_Match object at 0x001C1FA8>
>>> re.search('[^aeiou]y$', 'boy')     
>>>
>>> re.search('[^aeiou]y$', 'day')
>>>
>>> re.search('[^aeiou]y$', 'pita')   
>>>
  vacancy 匹配这个正则表达式,因为它以 cy 结尾,并且 c 不在 a、 e、 i、 o 和 u 之列。
  boy 不能匹配,因为它以 oy 结尾,并且你特别指出 y 之前的字符不可以是 o。 day 不能匹配是因为以 ay 结尾。
  pita 不匹配是因为不以 y 结尾。

例 17.5. 更多的 re.sub
>>> re.sub('y$', 'ies', 'vacancy')              
'vacancies'
>>> re.sub('y$', 'ies', 'agency')
'agencies'
>>> re.sub('([^aeiou])y$', r'\1ies', 'vacancy')
'vacancies'
  正则表达式把 vacancy 变为 vacancies, 把 agency 变为 agencies 正是你想要的。 注意,将 boy 变成 boies 是可行的,但是永远不会发生,因为 re.search 首先确定是否应该应用 re.sub。
  顺便提一下,可以将两个正则表达式(一个确定规则适用与否,一个应用规则)合并在一起成为一个正则表达式。 这便是合并后的样子。 它的大部分已经很熟悉:你应用的是在 第 7.6 节 “个案研究: 解析电话号码” 学过的记忆组(remembered group)记住 y 之前的字符。然后再替换字符串,你使用一个新的语法 \1,这意味着: “嘿!记得前面的第一个组吗? 把它放这儿”。 就此而言,记住了 y 之前的 c ,然后你做替换工作,你将 c 替换到 c 的位置,并将 ies 替换到 y 的位置。 (如果你有不只一个组则可以使用 \2 或者 \3 等等。)

正则表达式替换非常强大,并且 \1 语法使之更加强大。 但是将整个操作放在一个正则表达式中仍然晦涩难懂,也不能与前面描述的复数规则直接呼应。 你原来列出的规则,比如 “如果单词以 S, X 或者 Z 结尾,结尾追加 ES”。 如果你在函数中看到两行代码描述 “如果单词以 S, X 或者 Z 结尾,结尾追加 ES”,更加直观些。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
327#
 楼主| 发表于 2006-7-19 01:00 | 只看该作者
17.3. plural.py, 第 2 阶段
现在你将增加一个抽象过程。 你从定义一个规则列表开始:如果这样,就做那个,否则判断下一规则。 让我们暂时将程序一部分复杂化以便使另一部分简单化。

例 17.6. plural2.py
[PHP]

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)            

。。。。。。。。。。。。
[/PHP]

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

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
328#
 楼主| 发表于 2006-7-19 01:00 | 只看该作者
这个抽象过程有些令人迷惑, 试着剖析函数看看实际的等价内容。 这个 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 列表指定在什么相对位置调用这个新匹配和新规则应用。

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

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
329#
 楼主| 发表于 2006-7-19 01:01 | 只看该作者
17.4. plural.py, 第 3 阶段
将每个匹配和规则应用分别制作成函数没有必要。 你从来不会直接调用它们:你把它们定义于 rules 列表之中并从那里调用它们。 让我们隐去他们的函数名而抓住规则定义的主线。

例 17.8. plural3.py

import re

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)
    )
   )                                          

def plural(noun):                             
    for matchesRule, applyRule in rules:      
        if matchesRule(noun):                 
            return applyRule(noun)            
  这与第 2 阶段定义的规则是一样的。惟一的区别是不再定义 match_sxz 和 apply_sxz 之类的函数,而是以 lambda 函数 法将这些函数的内容直接 “嵌入” rules 列表本身。 .
  注意 plural 函数完全没有变化,还是反复于一系列的规则函数,检查第一个匹配规则,如果返回真调用第二个应用规则并返回值。 和前面一样,给定单词返回单词。 唯一的区别是规则函数被内嵌定义,化名作 lambda 函数。 但是 plural 函数并不在乎它们是如何定义的,只是拿到规则列表,闭着眼睛干活。

现在添加一条新的规则,所有你要做的就是直接在 rules 列表之中定义函数:一个匹配规则,一个应用规则。 这样内嵌的规则函数定义方法使得没必要的重复很容易被发现。 你有四对函数,它们采用相同的模式。 匹配函数就是调用 re.search,应用函数就是调用 re.sub。 让我们提炼出这些共同点。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
330#
 楼主| 发表于 2006-7-19 01:01 | 只看该作者
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 是一个动态生成其它函数的函数。 它将 pattern, search 和 replace (实际上是一个元组,但很快就会变得不止于此),通过使用 lambda 语法构建一个接受单参数(word)并以传递给 buildMatchAndApplyFunctions 的 pattern 和 传递给新函数的 word 调用 re.search 的匹配函数! 哇塞!
  构建应用规则函数的方法相同。 应用规则函数是一个接受单参数并以传递给 buildMatchAndApplyFunctions 的 search 和 replace 以及传递给这个应用规则函数的 word 调用 re.sub 的函数。在一个动态函数中应用外部参数值的技术被称作 闭合(closures)。你实际上是在应用规则函数中定义常数:接受一个参数(word),但随后它与定义应用规则函数时设置的另外两个值 (search 和 replace)一起工作。
  最终, buildMatchAndApplyFunctions 函数返回一个包含两个值的元组:你刚刚创建的两个函数。你在这些函数中定义的(matchFunction 中的 pattern 以及 applyFunction 中的 search 和 replace) 保留在这些函数中,由 buildMatchAndApplyFunctions 一同返回。 这简直太酷了。

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

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表