楼主: 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
171#
 楼主| 发表于 2006-7-15 21:18 | 只看该作者
9.2. 包
实际上解析一个 XML 文档是很简单的:只要一行代码。但是,在你接触那行代码前,需要暂时岔开一下,讨论一下包。

例 9.5. 载入一个 XML 文档 (偷瞥一下)
>>> from xml.dom import minidom
>>> xmldoc = minidom.parse('~/diveintopython/common/py/kgp/binary.xml')  这个语法你之前没有见过。它看上去很像我们所知并且喜欢的 from module import ,但是"." 使得它好像不止是import那么简单。事实上,xml 是我们所知的包,dom 是xml 中嵌套的包,而 minidom 是 xml.dom 中的模块。

听起来挺复杂的,其实不是。看一下确切的实现可能会有帮助。包不过是模块的目录;嵌套包是子目录。一个包(或一个嵌套包)中的模块也只是 .py 文件罢了,永远都是,只是它们是在一个子目录中,而不是在你的 Python 安装环境的主 lib/ 目录下。

使用道具 举报

回复
论坛徽章:
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
172#
 楼主| 发表于 2006-7-15 21:18 | 只看该作者
例 9.6. 包的文件布局
[php]
Python21/           Python 安装根目录 (可执行文件的所在地)
|
+--lib/             库目录 (标准库模块的所在地)
   |
   +-- xml/         xml包 (实际上目录中还有其它东西)
       |
       +--sax/      xml.sax包 (也只是一个目录)
       |
       +--dom/      xml.dom包 (包含 minidom.py)
       |
       +--parsers/  xml.parsers包 (内部使用)
.........
[/php]

所以你说from xml.dom import minidom,Python 认为它的意思是“在 xml 目录中查找 dom 目录,然后在其中查找 minidom 模块,接着导入它并以 minidom 命名 ”。但是 Python 更聪明;你不仅可以导入包含在一个包中的所有模块,还可以从包的模块中有选择地导入指定的类或者函数。语法都是一样的; 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
173#
 楼主| 发表于 2006-7-18 23:34 | 只看该作者
例 9.7. 包也是模块
>>> from xml.dom import minidom         
>>> minidom
<module 'xml.dom.minidom' from 'C:\Python21\lib\xml\dom\minidom.pyc'>
>>> minidom.Element
<class xml.dom.minidom.Element at 01095744>
>>> from xml.dom.minidom import Element
>>> Element
<class xml.dom.minidom.Element at 01095744>
>>> minidom.Element
<class xml.dom.minidom.Element at 01095744>
>>> from xml import dom                 
>>> dom
<module 'xml.dom' from 'C:\Python21\lib\xml\dom\__init__.pyc'>
>>> import xml                          
>>> xml
<module 'xml' from 'C:\Python21\lib\xml\__init__.pyc'>  这里你正从一个嵌套包(xml.dom)中导入一个模块(minidom)。结果就是 minidom 被导入到了你(程序)的命名空间中,为了能够引用 minidom 模块中的类(比如 Element),你必须在它们的类名前面加上模块名。
  这里你正从一个来自嵌套包(xml.dom)的模块(minidom)中导入一个类(Element)。结果就是 Element 直接导入到了你(程序)的命名空间中。注意,这样做并不会干扰以前的导入;现在 Element 类可以用两种方式引用了(但其实是同一个类)。
  这里你正在导入 dom 包(xml 的一个嵌套包),并将其作为自己或者内部的一个模块。一个包的任何层次都可以视为一个模块,一会就会看到。它甚至可以拥有自己的属性和方法,就像你在前面看到过的模块。
  这里你正在将根层次的 xml 包作为一个模块导入。

那么如何才能导入一个包(它不过是磁盘上的一个目录)并使其成为一个模块(它总是在磁盘上的一个文件)呢?答案就是神奇的 __init__.py 文件。你明白了吧,包不只是目录,它们是包含一个特殊文件 __init__.py 的目录。这个文件定义了包的属性和方法。例如,xml.dom 包含了 Node 类,它在xml/dom/__init__.py中有所定义。当你将一个包作为模块导入(比如从 xml 导入 dom)的时候,实际上导入了它的 __init__.py 文件。


一个包是一个其中带有特殊文件 __init__.py 的目录。__init__.py 文件定义了包的属性和方法。其实它可以什么也不定义;可以只是一个空文件,但是必须要存在。如果 __init__.py 不存在,这个目录就仅仅是一个目录,而不是一个包,它就不能被导入或者包含其它的模块和嵌套包。

那为什么非得用包呢?恩,它们提供了在逻辑上将相关模块归为一组的方法。不使用其中带有 sax 和 dom 的 xml 包,作者也可以选择将所有的 sax 功能放入 xmlsax.py中,并将所有的 dom 功能放入 xmldom.py中,或者干脆将所有东西放入单个模块中。但是这样可能不实用(在写到这儿时,XML 包已经超过了3000行代码)并且很难管理(独立的源文件意味着多个人可以同时在不同的地方进行开发)。

如果你发现自己正在用 Python 编写一个大型的子系统(或者,很有可能,当你意识到你的小型子系统已经成长为一个大型子系统时),你应该花费些时间设计一个好的包架构。它是 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
174#
 楼主| 发表于 2006-7-18 23:34 | 只看该作者
9.3. XML 解析
正如我说的,实际解析一个 XML 文档是非常简单的:只要一行代码。从这里出发到哪儿去就是你自己的事了。

例 9.8. 载入一个 XML 文档 (这次是真的)
>>> from xml.dom import minidom                                          
>>> xmldoc = minidom.parse('~/diveintopython/common/py/kgp/binary.xml')  
>>> xmldoc                                                               
<xml.dom.minidom.Document instance at 010BE87C>
>>> print xmldoc.toxml()                                                
<?xml version="1.0" ?>
<grammar>
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
<ref id="byte">
  <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
<xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
</ref>
</grammar>  正如在上一章节看到的,该语句从 xml.dom 包中导入 minidom 模块。
  这就是进行所有工作的一行代码:minidom.parse 接收一个参数并返回 XML 文档解析后的表示形式。这个参数可以是很多东西;在本例中,它只是我本地磁盘上一个 XML 文档的文件名。(为了继续执行,你需要将路径改为指向下载的例子所在的目录。)但是你也可以传入一个 文件对象,或甚至是一个类似文件的对象。这样你就可以在本章后面好好利用这一灵活性了。
  从 minidom.parse 返回的对象是一个 Document 对象,它是 Node 类的一个子对象。这个Document 对象是联锁的 Python 对象的一个复杂树状结构的根层次,这些 Python 对象完整表示了传给 minidom.parse 的 XML 文档。
  toxml 是 Node 类的一个方法(因此可以在从 minidom.parse 中得到的 Document 对象上使用)。toxml 打印出了 Node 表示的 XML。对于 Document 节点,这样就会打印出整个 XML 文档。

现在内存中已经有了一个 XML 文档了,你可以开始遍历它了。

使用道具 举报

回复
论坛徽章:
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
175#
 楼主| 发表于 2006-7-18 23:35 | 只看该作者
例 9.9. 获取子节点
>>> xmldoc.childNodes   
[<DOM Element: grammar at 17538908>]
>>> xmldoc.childNodes[0]
<DOM Element: grammar at 17538908>
>>> xmldoc.firstChild   
<DOM Element: grammar at 17538908>  每个 Node 都有一个 childNodes 属性,它是一个 Node 对象的列表。一个 Document 只有一个子节点,即 XML 文档的根元素(在本例中,是 grammar 元素)。
  为了得到第一个(在本例中,只有一个)子节点,只要使用正规的列表语法。回想一下,其实这里没有发生什么特别的;这只是一个由正规 Python 对象构成的正规 Python 列表。
  鉴于获取某个节点的第一个子节点是有用而且常见的行为,所以 Node 类有一个 firstChild 属性,它和childNodes[0]具有相同的语义。(还有一个 lastChild 属性,它和childNodes[-1]具有相同的语义。)

使用道具 举报

回复
论坛徽章:
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
176#
 楼主| 发表于 2006-7-18 23:35 | 只看该作者
例 9.10. toxml 用于任何节点
>>> grammarNode = xmldoc.firstChild
>>> print grammarNode.toxml()
<grammar>
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
<ref id="byte">
  <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
<xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
</ref>
</grammar>  由于 toxml 方法是定义在 Node 类中的,所以对任何 XML 节点都是可用的,不仅仅是 Document 元素。

使用道具 举报

回复
论坛徽章:
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
177#
 楼主| 发表于 2006-7-18 23:35 | 只看该作者
例 9.11. 子节点可以是文本
>>> grammarNode.childNodes                  
[<DOM Text node "\n">, <DOM Element: ref at 17533332>, \
<DOM Text node "\n">, <DOM Element: ref at 17549660>, <DOM Text node "\n">]
>>> print grammarNode.firstChild.toxml()   



>>> print grammarNode.childNodes[1].toxml()
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
>>> print grammarNode.childNodes[3].toxml()
<ref id="byte">
  <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
<xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
</ref>
>>> print grammarNode.lastChild.toxml()     


  查看 binary.xml 中的 XML ,你可能会认为 grammar 只有两个子节点,即两个 ref 元素。但是你忘记了一些东西:硬回车!在'<grammar>'之后,第一个'<ref>'之前是一个硬回车,并且这个文本算作 grammar 元素的一个子节点。类似的,在每个'</ref>'之后都有一个硬回车;它们都被当作子节点。所以grammar.childNodes实际上是一个有5个对象的列表:3个 Text 对象和两个 Element 对象。
  第一个子节点是一个 Text 对象,它表示在'<grammar>'标记之后、第一个'<ref>'标记之后的硬回车。
  第二个子节点是一个 Element 对象,表示了第一个 ref 元素。
  第四个子节点是一个 Element 对象,表示了第二个 ref 元素。
  最后一个子节点是一个 Text 对象,表示了在'</ref>'结束标记之后、'</grammar>' 结束标记之前的硬回车。

使用道具 举报

回复
论坛徽章:
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
178#
 楼主| 发表于 2006-7-18 23:35 | 只看该作者
例 9.12. Drilling down all the way to text
>>> grammarNode
<DOM Element: grammar at 19167148>
>>> refNode = grammarNode.childNodes[1]
>>> refNode
<DOM Element: ref at 17987740>
>>> refNode.childNodes                  
[<DOM Text node "\n">, <DOM Text node "  ">, <DOM Element: p at 19315844>, \
<DOM Text node "\n">, <DOM Text node "  ">, \
<DOM Element: p at 19462036>, <DOM Text node "\n">]
>>> pNode = refNode.childNodes[2]
>>> pNode
<DOM Element: p at 19315844>
>>> print pNode.toxml()                 
<p>0</p>
>>> pNode.firstChild                    
<DOM Text node "0">
>>> pNode.firstChild.data               
u'0'  正如你在前面的例子中看到的,第一个ref元素是grammarNode.childNodes[1],因为childNodes[0]是一个代表硬回车的 Text 节点。
  ref元素有它自己的子节点集合,一个表示硬回车,一个独立表示空格的,一个用于p元素的,诸如此类。
  你甚至可以在这里使用 toxml 方法,深深嵌套在文档中。
  p元素只有一个子节点(在这个例子中,你无法知道这一点,但是如果你不信,可以看看pNode.childNodes),而且它是表示单字符'0'的一个 Text 节点。
  Text 节点的.data属性可以向你提供文本节点真正代表的字符串。但是字符串前面的'u'是什么意思呢?答案将自己专门有一部分来论述。

使用道具 举报

回复
论坛徽章:
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
179#
 楼主| 发表于 2006-7-18 23:36 | 只看该作者
9.4. Unicode
Unicode 是一个系统,用来表示世界上所有不同语言的字符。当 Python 解析一个 XML 文档时,所有的数据都是以unicode的形式保存在内存中的。

一会儿你就会了解,但首先,先看一些背景知识。

历史注解. 在unicode之前,对于每一种语言都存在独立的字符编码系统,每个系统都使用相同的数字(0-255)来表示这种语言的字符。一些语言(象俄语)对于如何表示相同的字符还有几种有冲突的标准;另一些语言(象日语)拥有太多的字符,需要多个字符集。在系统之间进行文档交流是困难的,因为对于一台计算机来说,没有方法可以识别出文档的作者使用了哪种编码模式;计算机看到的只是数字,并且这些数字可以表示不同的东西。接着考虑到试图将这些文档存放到同一个地方(比如在同一个数据库表中);你需要在每段文本的旁边保存字符的编码,并且确保在传递文本的同时将编码也进行传递。接着考虑多语言文档,即在同一文档中使用了不同语言的字符。(比较有代表性的是使用转义符来进行模式切换;扑,我们处于俄语 koi8-r 模式,所以字符 241 表示这个;扑,现在我们处于 Mac 希腊语模式,所以字符 241 表示其它什么。等等。)这些就是unicode被设计出来要解决的问题。

为了解决这些问题,unicode用一个 2 字节数字表示每个字符,从 0 到 65535。[5] 每个 2 字节数字表示至少在一种世界语言中使用的一个唯一字符。(在多种语言中都使用的字符具有相同的数字码。)这样就确保每个字符一个数字,并且每个数字一个字符。Unicode数据永远不会模棱两可。

当然,仍然还存在着所有那些遗留的编码系统的情况。例如,7位 ASCII,它可以将英文字符存诸为从0到127的数值。(65是大写字母“A”,97是小写字母“a”,等等。)英语有着非常简单的字母表,所以它可以完全用7位 ASCII 来表示。象法语、西班牙语和德语之类的西欧语言都使用叫做ISO-8859-1的编码系统(也叫做“latin-1”),它使用7位 ASCII 字符表示从0到127的数字,但接着扩展到了128-255的范围来表示象n上带有一个波浪线(241),和u上带有两个点(252)的字符。Unicode使用同7位 ASCII 码一样的字符表示0到127,同ISO-8859-1一样的字符表示128到255,接着使用剩余的数字,256到65535,扩展到表示其它语言的字符。

在处理unicode数据时,在某些地方你可能需要将数据转换回这些遗留编码系统之一。例如,为了同其它一些计算机系统集成,这些系统期望它的数据使用一种特定的单字节编码模式,或将数据打印输出到一个非unicode识别终端或打印机。或将数据保存到一个明确指定编码模式的 XML 文档中。

在了解这个注解之后,让我们回到 Python上来。

从2.0版本开始,Python 在整个语言的基础上已经支持unicode。XML 包使用unicode来保存所有解析了的 XML 数据,而且你可以在任何地方使用unicode。

使用道具 举报

回复
论坛徽章:
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
180#
 楼主| 发表于 2006-7-18 23:36 | 只看该作者
例 9.13. unicode介绍
>>> s = u'Dive in'            
>>> s
u'Dive in'
>>> print s                  
Dive in  为了创建一个unicode字符串而不是通常的 ASCII 字符串,要在字符串前面加上字母“u”。注意这个特殊的字符串没有任何非 ASCII 的字符。这样很好;unicode是 ASCII 的一个超集(一个非常大的超集),所以任何正常的 ASCII 都可以以unicode形式保存起来。
  在打印字符串时,Python 试图将字符串转换为你的默认编码,通常是 ASCII 。(过会儿有更详细的说明。)因为组成这个unicode字符串的字符都是 ASCII 字符,打印结果与打印正常的 ASCII 字符串是一样的;转换是无缝的,而且如果你没有注意到s是一个unicode字符串的话,你永远也不会注意到两者之间的差别。

使用道具 举报

回复

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

本版积分规则 发表回复

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