楼主: 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
181#
 楼主| 发表于 2006-7-18 23:36 | 只看该作者
例 9.14. 存储非 ASCII 字符
>>> s = u'La Pe\xf1a'         
>>> print s                  
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)
>>> print s.encode('latin-1')
La Pe&ntilde;a  unicode真正的优势,理所当然的是它保存非 ASCII 字符的能力,例如西班牙语的“&ntilde;”(n上带有一个波浪线)。用来表示波浪线n的unicode字符编码是十六进制的0xf1 (十进制的241),你可以象这样输入:\xf1  
  还记得我说过 print 函数会尝试将unicode字符串转换为 ASCII,这样就可以打印它了吗?嗯,在这里将不会起作用,因为你的unicode字符串包含非 ASCII 字符,所以 Python 会引发UnicodeError异常。  
  这儿就是将unicode转换为其它编码模式起作用的地方。s是一个unicode字符串,但 print 只能打印正常的字符串。为了解决这个问题,我们调用 encode 方法(它可以用于每个unicode字符串)将unicode字符串转换为指定编码模式的正常字符串。我们向此函数传入一个参数。在本例中,我们使用 latin-1 (也就是大家知道的 iso-8859-1),它包括带波浪线的n(然而缺省的 ASCII 编码模式不包括,因为它只包含数值从 0 到 127 的字符)。

还记得我说过:一旦需要从一个unicode得到一个正常字符串,Python通常默认将unicode转换成 ASCII 吗?嗯,这个默认编码模式是一个可以定制的选项。

使用道具 举报

回复
论坛徽章:
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
182#
 楼主| 发表于 2006-7-18 23:36 | 只看该作者
例 9.15. sitecustomize.py
# sitecustomize.py                  
# this file can be anywhere in your Python path,
# but it usually goes in ${pythondir}/lib/site-packages/
import sys
sys.setdefaultencoding('iso-8859-1')
  sitecustomize.py是一个特殊的脚本;Python 会在启动的时候导入它,所以在其中的任何代码都将自动运行。就像注解中提到的那样,它可以放在任何地方(只要 import 能够找到它),但是通常它位于 Python 的lib目录的site-packages目录中。
  恩,setdefaultencoding 函数设置默认编码。Python 会在任何需要自动将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
183#
 楼主| 发表于 2006-7-18 23:36 | 只看该作者
例 9.16. 设置默认编码的效果
>>> import sys
>>> sys.getdefaultencoding()
'iso-8859-1'
>>> s = u'La Pe\xf1a'
>>> print s                  
La Pe&ntilde;a  这个例子假设你已经按前一个例子中的改动对sitecustomize.py文件做了修改,并且已经重启了 Python。如果你的默认编码还是'ascii',可能你就没有正确设置sitecustomize.py 文件,或者是没有重新启动 Python。默认的编码只会在 Python 启动的时候改变;之后就不能改变了。(由于一些古怪的编程技巧,我没有马上深入,你甚至不能在 Python 启动之后调用sys.setdefaultencoding函数。仔细研究site.py,并搜索“setdefaultencoding”去发现为什么吧。)
  现在默认的编码模式已经包含了你在字符串中使用的所有字符,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
184#
 楼主| 发表于 2006-7-18 23:37 | 只看该作者
例 9.17. 指定.py文件的编码
如果你打算在你的 Python 代码中保存非 ASCII 字符串,你需要在每个文件的顶端加入编码声明来指定每个.py文件的编码。这个声明定义了.py文件的编码为UTF-8:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
现在,想想 XML 中的编码应该是怎样的呢?不错的是,每一个 XML 文档都有指定的编码。重复一下,ISO-8859-1是西欧语言存放数据的流行编码方式。KOI8-R是俄语流行的编码方式。编码,如果指定了的话,都在 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
185#
 楼主| 发表于 2006-7-18 23:37 | 只看该作者
例 9.18. russiansample.xml

<?xml version="1.0" encoding="koi8-r"?>      
<preface>
<title>Предисловие</title>                    
</preface>  这是从一个真实的俄语 XML 文档中提取出来的示例;它就是这本书俄语翻译版的一部分。注意,编码koi8-r是在首部指定的。
  这些是古代斯拉夫语的字符,就我所知,它们用来拼写俄语单词“Preface”。如果你在一个正常文本编辑器中打开这个文件,这些字符非常象乱码,因为它们使用了koi8-r编码模式进行编码,但是却以iso-8859-1编码模式进行显示。

例 9.19. 解析russiansample.xml
>>> from xml.dom import minidom
>>> xmldoc = minidom.parse('russiansample.xml')
>>> title = xmldoc.getElementsByTagName('title')[0].firstChild.data
>>> title                                       
u'\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435'
>>> print title                                 
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)
>>> convertedtitle = title.encode('koi8-r')     
>>> convertedtitle
'\xf0\xd2\xc5\xc4\xc9\xd3\xcc\xcf\xd7\xc9\xc5'
>>> print convertedtitle                        
Предисловие  我假设在这里你将前一个例子以russiansample.xml为名保存在当前目录中。也出于完整性的考虑,我假设你已经删除了sitecustomize.py文件,将缺省编码改回到'ascii',或至少将setdefaultencoding一行注释起来了。
  注意title标记的文本数据(现在在title变量中,幸亏有 Python 函数的常串联,我快速地将它跳过去,并且在下一节之前不会进行解释)--在 XML 文档的title元素中的文本数据是以unicode保存的。
  打印title是不可能的,因为这个unicode字符串包哈了非 ASCII 字符,所以 Python 不能把它转换为 ASCII 因为它无法理解。
  你能够,但是,显式的将它转换为koi8-r,在本例中,我们得到一个(正常,非unicode)单字节字符的字符串(f0, d2, c5,等等),它是初始unicode字符串中字符koi8-r-编码的版本。
  打印koi8-r编码的字符串有可能会在你的屏幕上显示为乱码,因为你的 Python IDE 将这些字符作为 iso-8859-1的编码进行解析,而不是koi8-r编码。但是,至少它们能打印。(并且,如果你仔细看,当在一个不支持unicode的文本编辑器中打开最初的 XML 文档时,会看到相同的乱码。 Python 在解析 XML 文档时,将它从koi8-r转换到了unicode,你只不过是将它转换回来。)

总结一下,如果你以前从没有看到过unicode,倒是有些唬人,但是在 Python 处理unicode数据真是非常容易。如果你的 XML 文档都是7位的 ASCII(像本章中的例子),你差不多永远都不用考虑unicode。Python 在进行解析时会将 XML 文档中的 ASCII 数据转换为unicode,在任何需要的时候强制转换回为 ASCII,你甚至永远都不用注意。但是如果你要处理其它语言的数据,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
186#
 楼主| 发表于 2006-7-18 23:37 | 只看该作者
进一步阅读
  • Unicode.org是unicode标准的主页,包含了一个简要的技术简介
  • Unicode教程有更多关于如何使用 Python unicode函数的例子,包括甚至在并不真的需要时如何将unicode强制转换为 ASCII。
  • PEP 263涉及了何时、如何在你的.py文件中定义字符的更多细节。

使用道具 举报

回复
论坛徽章:
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
187#
 楼主| 发表于 2006-7-18 23:37 | 只看该作者
Footnotes
[5] 这一点,很不幸仍然 过分简单了。现在unicode已经扩展用来处理古老的汉字、韩文和日文文本,它们有太多不同的字符,以至于2字节的unicode系统不能全部表示。但当前 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
188#
 楼主| 发表于 2006-7-18 23:38 | 只看该作者
9.5. 搜索元素
通过一步步访问每一个节点的方式遍历 XML 文档可能很乏味。如果你正在寻找些特别的东西,又恰恰它们深深埋入了你的 XML 文档,有个捷径让你可以快速找到它:getElementsByTagName 。

在这部分,将使用 binary.xml 语法文件,它看上去是这样的:

例 9.20. binary.xml
<?xml version="1.0"?>
<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
<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>它有两个 ref,'bit'和'byte'。一个位是'0'或者'1',而一个字节是8个位。

例 9.21. getElementsByTagName 介绍
>>> from xml.dom import minidom
>>> xmldoc = minidom.parse('binary.xml')
>>> reflist = xmldoc.getElementsByTagName('ref')
>>> reflist
[<DOM Element: ref at 136138108>, <DOM Element: ref at 136144292>]
>>> print reflist[0].toxml()
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
>>> print reflist[1].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>
  getElementsByTagName 接收一个参数,即要找的元素的名称。它返回一个 Element 对象的列表,列表中的对象都是有指定名称的 XML 元素。在本例中,你能找到两个ref元素。

使用道具 举报

回复
论坛徽章:
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
189#
 楼主| 发表于 2006-7-18 23:38 | 只看该作者
例 9.22. 每个元素都是可搜索的
>>> firstref = reflist[0]                     
>>> print firstref.toxml()
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
>>> plist = firstref.getElementsByTagName("p"
>>> plist
[<DOM Element: p at 136140116>, <DOM Element: p at 136142172>]
>>> print plist[0].toxml()                     
<p>0</p>
>>> print plist[1].toxml()
<p>1</p>  继续前面的例子,在reflist中的第一个对象是'bit' ref元素。
  你可以在这个 Element 上使用相同的 getElementsByTagName 方法来寻找所有在'bit' ref 元素中的<p>元素。
  和前面一样,getElementsByTagName 方法返回一个找到元素的列表。在本例中,你有两个,每“位”使用一个。

例 9.23. 搜索实际上是递归的
>>> plist = xmldoc.getElementsByTagName("p"
>>> plist
[<DOM Element: p at 136140116>, <DOM Element: p at 136142172>, <DOM Element: p at 136146124>]
>>> plist[0].toxml()                        
'<p>0</p>'
>>> plist[1].toxml()
'<p>1</p>'
>>> plist[2].toxml()                        
'<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>'  仔细注意这个例子和前面例子之间的不同。前面,你是在firstref中搜索 p 元素,但是这里你是在xmldoc中搜索 p 元素,xmldoc是代表了整个 XML 文档的根层对象。这样就会找到嵌套在 ref 元素(它嵌套在根 grammar 元素中)中的 p 元素。
  前两个 p 元素在第一个 ref 内('bit' ref)。
  后一个 p 元素在第二个 ref 中('byte' ref)。

使用道具 举报

回复
论坛徽章:
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
190#
 楼主| 发表于 2006-7-18 23:38 | 只看该作者
9.6. 访问元素属性
XML 元素可以有一个或者多个属性,一旦你已经解析了一个 XML 文档,访问它们就太简单了。

在这部分中,将使用 binary.xml 语法文件,你在上一节中已经看到过了。


这部分由于某个涵义重叠的术语可能让人有点糊涂。在一个 XML 文档中,元素可以有属性,而 Python 对象也有属性。当你解析一个 XML 文档时,你得到了一组 Python 对象,它们代表 XML 文档中的所有片段,同时有些 Python 对象代表 XML 元素的属性。但是表示(XML)属性的(Python)对象也有(Python)属性,它们用于访问对象表示的(XML)属性。我告诉过你它让人糊涂。我会公开提出关于如何更明显地区分这些不同的建议。  

例 9.24. 访问元素属性
>>> xmldoc = minidom.parse('binary.xml')
>>> reflist = xmldoc.getElementsByTagName('ref')
>>> bitref = reflist[0]
>>> print bitref.toxml()
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
>>> bitref.attributes         
<xml.dom.minidom.NamedNodeMap instance at 0x81e0c9c>
>>> bitref.attributes.keys()   
[u'id']
>>> bitref.attributes.values()
[<xml.dom.minidom.Attr instance at 0x81d5044>]
>>> bitref.attributes["id"]   
<xml.dom.minidom.Attr instance at 0x81d5044>  每个 Element 对象都有一个称为attributes的属性,它是一个 NamedNodeMap 对象。听上去挺吓人的,其实不然,因为 NamedNodeMap 是一个行为像字典的对象,所以你已经知道怎么使用它了。
  将 NamedNodeMap 视为一个字典,你可以通过attributes.keys()获得属性名称的一个列表。这个元素只有一个属性,'id'。
  属性名称,像其它 XML 文档中的文本一样,都是以unicode保存的。
  再次将 NamedNodeMap 视为一个字典,你可以通过attributes.values()获取属性值的一个列表。这些值本身是 Attr 类型的对象。你将在下一个例子中看到如何获取对象的有用信息。
  仍然把 NamedNodeMap 视为一个字典,你可以通过常用的字典语法和名称访问单个的属性。(那些非常认真的读者将已经知道 NamedNodeMap 类是如何实现这一技巧的:通过定义一个__getitem__ 特殊方法。它的读者可能乐意接受这一事实:他们不需要理解它是如何工作的就可以有效地使用它。)

例 9.25. 访问单个属性
>>> a = bitref.attributes["id"]
>>> a
<xml.dom.minidom.Attr instance at 0x81d5044>
>>> a.name  
u'id'
>>> a.value
u'bit'  Attr 对象完整代表了单个 XML 元素的单个 XML 属性。属性的名称(与你在bitref.attributes NamedNodeMap 的伪目录中寻找的对象同名)保存在a.name中。
  这个 XML 属性的真实文本值保存在a.value中。


类似于字典,一个 XML 元素的属性没有顺序。属性可以以某种顺序偶然列在最初的 XML 文档中,而在 XML 文档解析为 Python 对象时,Attr 对象以某种顺序偶然列出,这些顺序都是任意的,没有任何特别的含义。你应该总是使用名称来访问单个属性,就像字典的键一样。

使用道具 举报

回复

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

本版积分规则 发表回复

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