- 第 1 章 安装 Python
- 1.2. Windows 上的 Python
- 1.3. Mac OS X 上的 Python
- 1.4. Mac OS 9 上的 Python
- 1.5. RedHat Linux 上的 Python
- 1.6. Debian GNU/Linux 上的 Python
- 1.7. 从源代码安装 Python
- 1.8. 使用 Python 的交互 Shell
- 1.9. 小结
- 第 2 章 第一个 Python 程序
- 2.2. 函数声明
- 2.3. 文档化函数
- 2.4. 万物皆对象
- 2.5. 代码缩进
- 2.6. 测试模块
- 第 3 章 内置数据类型
- 3.2. List 介绍
- 3.3. Tuple 介绍
- 3.4. 变量声明
- 3.5. 格式化字符串
- 3.6. 映射 list
- 3.7. 连接 list 与分割字符串
- 3.8. 小结
- 第 4 章 自省的威力
- 4.2. 使用可选参数和命名参数
- 4.3. 使用 type、str、dir 和其它内置函数
- 4.4. 通过 getattr 获取对象引用
- 4.5. 过滤列表
- 4.6. and 和 or 的特殊性质
- 4.7. 使用 lambda 函数
- 4.8. 全部放在一起
- 4.9. 小结
- 第 5 章 对象和面向对象
- 5.2. 使用 from module import 导入模块
- 5.3. 类的定义
- 5.4. 类的实例化
- 5.5. 探索 UserDict: 一个封装类
- 5.6. 专用类方法
- 5.7. 高级专用类方法
- 5.8. 类属性介绍
- 5.9. 私有函数
- 5.10. 小结
- 第 6 章 异常和文件处理
- 6.2. 与文件对象共事
- 6.3. for 循环
- 6.4. 使用 sys.modules
- 6.5. 与 Directory 共事
- 6.6. 全部放在一起
- 6.7. 小结
- 第 7 章 正则表达式
- 7.2. 个案研究:街道地址
- 7.3. 个案研究:罗马字母
- 7.4. 使用{n,m} 语法
- 7.5. 松散正则表达式
- 7.6. 个案研究: 解析电话号码
- 7.7. 小结
- 第 8 章 HTML 处理
- 8.2. sgmllib.py 介绍
- 8.3. 从 HTML 文档中提取数据
- 8.4. BaseHTMLProcessor.py 介绍
- 8.5. locals 和 globals
- 8.6. 基于 dictionary 的字符串格式化
- 8.7. 给属性值加引号
- 8.8. dialect.py 介绍
- 8.9. 全部放在一起
- 8.10. 小结
- 第 9 章 XML 处理
- 9.2. 包
- 9.3. XML 解析
- 9.4. Unicode
- 9.5. 搜索元素
- 9.6. 访问元素属性
- 9.7. Segue
- 第 10 章 Scripts 和 Streams
- 10.2. 标准输入、输出和错误
- 10.3. 缓冲节点查询
- 10.4. 查找节点的直接子节点
- 10.5. 通过节点类型创建独立的处理句柄 Creating separate handlers by node type
- 10.6. 处理命令行参数
- 10.7. 全部放在一起
- 10.8. 小结
- 第 11 章 HTTP Web 服务
- 11.2. 避免通过 HTTP 重复地获取数据
- 11.3. HTTP 的特性
- 11.4. 调试 HTTP web 服务
- 11.5. 设置 User-Agent
- 11.6. 处理 Last-Modified 和 ETag
- 11.7. 处理重定向
- 11.8. 处理被压缩的数据
- 11.9. 全部放在一起
- 11.10. 小结
- 第 12 章 SOAP Web 服务
- 12.2. 安装 SOAP 库
- 12.3. 步入 SOAP
- 12.4. SOAP 网络服务查错
- 12.5. WSDL 介绍
- 12.6. 以 WSDL 进行 SOAP 内省
- 12.7. 搜索 Google
- 12.8. SOAP 网络服务故障排除
- 12.9. 小结
- 第 13 章 单元测试
- 13.2. 深入
- 13.3. 介绍 romantest.py
- 13.4. 正面测试(Testing for success)
- 13.5. 负面测试(Testing for failure)
- 13.6. 完备性检测(Testing for sanity)
- 第 14 章 以测试优先为原则的编程
- 14.2. roman.py, 第 2 阶段
- 14.3. roman.py, 第 3 阶段
- 14.4. roman.py, 第 4 阶段
- 14.5. roman.py, 第 5 阶段
- 第 15 章 重构
- 15.2. 应对需求变化
- 15.3. 重构
- 15.4. 后记
- 15.5. 小结
- 第 16 章 有效编程(Functional Programming)
- 16.2. 找到路径
- 16.3. 过滤已访问列表
- 16.4. 关联已访问列表
- 16.5. 数据中心思想编程
- 16.6. 动态导入模块
- 16.7. 全部放在一起
- 16.8. 小结
- 第 17 章 动态函数
- 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. 小结
- 第 18 章 性能优化
- 18.2. 使用 timeit 模块
- 18.3. 优化正则表达式
- 18.4. 优化字典查找
- 18.5. 优化列表操作
- 18.6. 优化字符串操作
- 18.7. 小结
- 附录 A. 进一步阅读
- 附录 B. 五分钟回顾
- 附录 C. 技巧和窍门
- 附录 D. 示例清单
- 附录 E. 修订历史
- 附录 F. 关于本书
- 附录 G. GNU Free Documentation License
- G.1. Applicability and definitions
- G.2. Verbatim copying
- G.3. Copying in quantity
- G.4. Modifications
- G.5. Combining documents
- G.6. Collections of documents
- G.7. Aggregation with independent works
- G.8. Translation
- G.9. Termination
- G.10. Future revisions of this license
- G.11. How to use this License for your documents
- 附录 H. Python license
- H.B. Terms and conditions for accessing or otherwise using Python
8.9. 全部放在一起
8.9. 全部放在一起
到了该将迄今为止我们已经学过并用得不错的东西放在一起的时候了。我希望您专心些。
例 8.20. translate 函数, 第 1 部分
def translate(url, dialectName="chef"): import urllib sock = urllib.urlopen(url) htmlSource = sock.read() sock.close()
这个 translate 函数有一个 可选参数 dialectName,它是一个字符串,指出我们将使用的方言。一会我们就会看到它是如何使用的。 | |
嘿,等一下,在这个函数中有一个 import 语句!它在 Python 中完全合法。您已经习惯了在一个程序的前面看到 import 语句,它意味着导入的模块在程序的任何地方都是可用的。但您也可以在一个函数中导入模块,这意味着导入的模块只能在函数中使用。如果您有一个只能用在一个函数中的模块,这是一个简便的方法,使您的代码更模块化。 (当发现您周末的加班已经变成了一个 800行 的艺术作品,并且决定将其分割成一打可重用的模块时,您会感谢它的。) | |
现在我们得到了给定的URL的原始资料。 |
例 8.21. translate 函数, 第 2 部分: 奇妙而又奇妙
parserName = "%sDialectizer" % dialectName.capitalize() parserClass = globals()[parserName] parser = parserClass()
capitalize 是一个我们以前未曾见过的字符串方法;它只是将一个字符串的第一个字母变成大写,将其它的字母强制变成小写。与某个 字符串格式化合在一起使用后,我们就得到了一种方言的名字,接着将它转化为相应的方言变换器类的名字。如果 dialectName 是字符串 'chef',parserName 将是字符串 'ChefDialectizer'。 | |
我们有了一个字符串形式 (parserName) 的类名称,还有一个 dictionary (globals()) 形式的全局名字空间。合起来后,我们可以得到一个以前面字符串命名的类的引用。 (回想一下,类是对象,并且它们可以象其它对象一样赋值给一个变量。) 如果 parserName 是字符串 'ChefDialectizer',parserClass 将是类 ChefDialectizer。 | |
最后,我们拥有了一个类对象 (parserClass),接着我们想要生成这个类的一个实例。好,我们已经知道如何去做了: 象函数一样调用类。这个类保存在一个局部变量中的事实完全不会有什么影响;我们只是象函数一样调用这个局部变量,取出这个类的一个实例。如果 parserClass 是类 ChefDialectizer,parser 将是类 ChefDialectizer 的一个实例。 |
怎么这么麻烦?毕竟只有三个 Dialectizer 类;为什么不只使用一个 case 语句? (噢,在 Python 中不存在 case 语句,但为什么不只使用一组 if 语句呢?) 理由之一是: 可扩展性。这个 translate 函数完全不用关心我们定义了多少个方言变换器类。设想一下,如果我们明天定义了一个新的 FooDialectizer 类,把 'foo' 作为 dialectName 传给 translate , translate 也能工作。
甚至会更好,设想将 FooDialectizer 放进一个独立的模块中,使用 from module import 将其导入。我们已经知道了,这样会将它 包含在 globals() 中 ,所以不用修改 translate ,它仍然可以正确运行,尽管 FooDialectizer 位于一个独立的文件中。
现在设想一下方言的名字是从程序外面的某个地方来的,也许是从一个数据库中,或从一个表格中的用户输入的值中。您可以使用任意多的服务端 Python 脚本架构来动态地生成网页;这个函数将接收在页面请求的查询字符串中的一个 URL 和一个方言名字 (两个都是字符串) ,接着输出 “翻译” 后的网页。
最后,设想一下,使用了一种插件架构的 Dialectizer 框架。您可以将每个 Dialectizer 类放在分别放在独立的文件中,在 dialect.py 中只留下 translate 函数。假定一种统一的命名模式,这个 translate 函数能够动态地从合适的文件中导入合适的类,除了方言名字外什么都不用给出。 (虽然您还没有看过动态导入,但我保证在后面的一章中会涉及到它。) 如果要加入一种新的方言,您只要在插件目录下加入一个以合适的名字命名的文件 (象 foodialect.py,它包含了 FooDialectizer 类) 。使用方言名 'foo' 来调用这个 translate 函数,将会查找 foodialect.py 模块,导入 FooDialectizer 类,这样就行了。
例 8.22. translate 函数, 第 3 部分
parser.feed(htmlSource) parser.close() return parser.output()
毕竟那只是假设,这个似乎会非常令人讨厌,但这个 feed 函数执行了全部的转换工作。我们拥有存在于单个字符串中的全部 HTML 源代码,所以我们只需要调用 feed 一次。然而,您可以按您的需要经常调用 feed,分析器将不停地进行分析。所以如果我们担心内存的使用 (或者我们已经知道了将要处理非常巨大的 HTML 页面) ,我们可以在一个循环中调用它,即我们读出一点 HTML 字节,就将其送进分析器。结果会是一样的。 | |
因为 feed 维护着一个内部缓冲区,当您完成时,应该总是调用分析器的 close 方法 (那怕您象我们做的一样,一次就全部送出) 。否则您可能会发现,输出丢掉了最后几个字节。 | |
回想一下,output 是我们在 BaseHTMLProcessor 上定义的函数,用来 将所有缓冲的输出片段连接起来 并且以单个字符串返回。 |
象这样,我们已经 “翻译” 了一个网页,除了给出一个 URL 和一种方言的名字外,什么都没有给出。
进一步阅读
- 您可能会认为我正在拿服务端脚本编程开玩笑。在我发现这个基于 web 的方言转换器之前,的确是这样认为的。 不幸的是,看不到它的源代码。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论