python 字符串反转
偶然看到论坛有人问python字符串怎么没有反转的方法,是很纳闷。后来找到了几个解决办法,还是很酷的说,记录以分享下。
>>> s = “abcdefg”
>>> s[::-1]
>>> a=list(s)
>>> a.reverse()
>>> “”.join(a)
>>> reduce(lambda x,y:y+x,s)
1 和3都很酷,也有python特色,2则是折中的一个土办法
偶然看到论坛有人问python字符串怎么没有反转的方法,是很纳闷。后来找到了几个解决办法,还是很酷的说,记录以分享下。
>>> s = “abcdefg”
>>> s[::-1]
>>> a=list(s)
>>> a.reverse()
>>> “”.join(a)
>>> reduce(lambda x,y:y+x,s)
1 和3都很酷,也有python特色,2则是折中的一个土办法
Python 3.0发布七个月之后,Python核心开发人员于2009年6月27日发布了新的Python 3.1版本。虽然此3.1版本只是对Python 3.0的一次小型升级,但是它不仅为开发者带来许多让人感兴趣的特性,同时在性能方面也有所改善。本文将分为三篇(核心语言篇、标准程序库篇、性能改善 篇)将为读者详细介绍Python 3.1版本在核心语言、标准程序库和性能改善方面的变化。
一、字符串的格式化
Python的最新版本为我们带来了讨人喜欢的格式字段的自动填数功能。我们知 道,许多程序中经常需要格式化字符串。Python 2.x版本使用的是类似[s]printf函数的百分号操作符,如下所示:
而Python 3.0则添加了更高级的字符串格式化功能,如下所示:
如今,Python 3.1则在字符串格式化方面又有了新的改进。对于Python 3.0来说,每当您想在格式串中引用位置参数时,您必须给出每个位置参数的索引。但是在Python 3.1中,您就可以将这些索引抛在脑后了,因为Python会依次替您填充这些参数:
二、 PEP-378:用于千位分隔符的格式说明符
在财务应用程序中,通常要在数字中使用千位分隔符。从事金融或者财会方面工作的人士是不这样写的“您欠 我$12345678”,而是“您欠我$12,345,678”,他们惯于使用逗号作为分隔符。那么,如何使用Python达到这种效果呢:
您可以利用其他区分符对 数字进行分组。这里的宽度说明符(这里为8)包括了逗号和小数点:
逗号通常作为默认的分隔 字符,如果要使用其他字符作为分隔字符的话,只需通过replace函数用您喜欢的字符替换逗号即可,具体如下所示:
当然,您还可以使用 format函数来作为字符串方法:
三、 Maketrans函数
利用maketrans()和translate()函数,我们可以使用一组字符来替换另一组字符。使用这一替换功能时,多 少有点繁琐,因为它要求使用maketrans()函数(该函数的作用是把输入字符映射到输出字符)建立一个转换表,然后,再把这个转换表传递给 translate()函数。当然,string模块仍然有它自己的maketrans()函数,不过Python 3.1不赞成使用它,而是赞赏使用单独的maketrans()函数来操作字节、字节数组和字符串。
下面的例子演示了如何使用maketrans()和 translate()函数处理字节对象。需要注意的是,用于字节的转换表具有256个表项(每一项对应于一个可能的字节),并且这个例子把大部分字节都 映射到它们自身,只有1,2和3例外,因为它们分别映射到了4,5和6。如下所示:
建好转换表之后,我们只 需把它传递给translate()函数即可,如下所示:
我们还可以传递其它的参 数作为要删除的字符:
我们可以看到,原来的5 已经从123456从删掉了,但是转换得到的5(请记住,我们的映射表将2转化为5)并没有删除。这说明,系统是先从原来的字符串中删除相应的字符,然后 才进行的转换操作。
字符串的转换稍微有些不同,字符串版本的maketrans函数返回的是一个字典:
四、与 数学有关的变化
3.1版本在与数学有关的方面也有所改变。
Int添加了一个bit_length方法
新版本中,int变量具有一个bit_length方法,它能返回该int变 量以二进制数表示的时候的位数。例如,数字19的二进制表示为10011,那么它的位数就是5:
浮点数的舍入
在Python 3.0以及早先的round()函数有点反复无常:如果您不指定精度的时候,它返回的是一个整数;如果指定精度的话,它返回的是您输入数据的类型:
在Python 3.1中,只要输入的数字是一个整数(即使它是用浮点数的形式表示的,例如1000.0),那么它总是返回一个整型数:
浮点数的表示
目前,实数在大部分的硬件 和操作系统中 都是用32位(单精度)或者64位(双精度)来表示的。然而,这会导致一些实数无法精确表示。由于计算机存储器的 二进制特性,某些数字利用十进制表示形式非常简洁,但是要是使用浮点方案表示的话,就要复杂了。举例来说,利用32位的单精度浮点数表示数字0.6,则为 0.59999999999999998:
对于这种表示方案,上面 的数字是为了做到尽可能的精确,但是对用户来说却很不友好。 Python 3.1使用了一个新算法,以便使得原值的表示尽可能得简练。所以在Python 3.1中,人们输入上面的数字,一个更简洁的表示:
这已经很精确了,除非遇 到算术运算。举例来说,表达式0.7+0.1的值用32位浮点表示法表示的话,它是 0.79999999999999993,而数字0.8的值用32位浮点数表示则是 0.80000000000000004。 这样一来,就意味着0.7+0.1并不等于0.8,这会导致一些问题。例如,下面的循环将永不休止:
输出的结果:
在Python 3.0中,repr()函数返回的是实际表示;而在Python 3.1中,它返回的是简洁表示。无论是在Python 3.0还是在Python 3.1中,print()函数显示的都是简洁表示:
Python语言还有一个称为decimal的模块,可用于精确的实数表示。它 使用一个不同的表示方案来表示浮点数,并且在内存运行的情况下,用尽量多的数位来表示一个实数——并且,当进行算术的时候不会出现舍入误差。在 Python 3.0中,Decimal类型使用了一种新方法来从一个字符串初始化它表示的值;在Python 3.1中,又增加了另一个新方法即from_float()来接收浮点数。注意,即使当使用from_float()的时候,Decimal模块也会比 32位更精确。
五、改 进的WITH语句
在Python 2.5中,WITH语句是作为一个__future__特性引入的,该语句的正式引入实际上是从Python 3.0开始的。到了Python 3.1版本,该语句已经能够支持更多的资源。最常见的情形是,它可以打开输入、输出文件并在处理完成后关闭它们。在Python 3.0中,我们要么使用嵌套的with语句,要么显式闭合在文件中。下面是一个Python 3.0的例子,它打开了一个输入文件,将其内容作为字符串读取,用字符串的title()方法处理内容,并将结果写到一个输出文件中。
这个示例中含有两个嵌套的 with语句,注意嵌套的with语句中的最后一行。当代码试图读取out.txt的时候,结果为空,因为此文件是被缓冲处理的,并且还没有写入。当此 with语句完成的时候,Python会关闭此文件,所以最后一行代码会认定out.txt的内容的确是大写文字。
看到嵌套的with语 句,是不是感觉有点头疼,呵呵。接下来,我们要打开两个两个文件,并在处理完成后关闭它们(如果您需要打开三个文件,那么就需要三个嵌套的with语 句)。 Python 3.1运行您使用单个WITH语句打开所有文件:
Python 3.1的另一项改进就是,gzip.GzipFile和bz2.BZ2File现在也能用于WITH语句。我们知道,这些都是压缩后的文件格式。下面的示 例代码将使用gzip文件和bz2文件来存储5000个字节的内容,并显示其尺寸。这里还有用到一些额外的Python 3特性,比如带有命名属性的统计结果和高级字符串格式化。
输出的结果:
六、小结
Python 3.0发布七个月之后,Python核心开发人员于2009年6月27日发布了新的Python 3.1版本。虽然此3.1版本只是对Python 3.0的一次小型升级,但是它不仅为开发者带来许多让人感兴趣的特性,同时在性能方面也有所改善。本文为读者详细介绍了Python 3.1版本在核心语言方面的变化,在接下来的文章中,我们将继续为读者介绍新版本中标准程序库和性能改善方面的变化。
Python 中要创建一个类的实例,要首先导入该类或者该类所属的模块,例如:
需 求:
你想复制一个对象.因为在Python 中,无论你把对象做为参数传递,做为函数返回值,都是引用传递的.
讨论:
标 准库中的copy模块提供了两个方法来实现拷贝.一个方法是copy,它返回和参数包含内容一样的对象.
>>> a = [1, 2, 3]
>>> b = a
>>> b.append(5)
>>> print a, b
[1, 2, 3, 5] [1, 2, 3, 5]
代码:
import sys
import os
import datetime
import time
class ArgsDealwith:
def arg_environment(self, args):
filepath = (’PYTHON_PATH’, ‘path’)
for i in filepath:
filename = os.environ.get(i,”%s is null.” % i)
print ‘%s:’ % i,’ ‘, filename
def arg_en(self, args):
filepath = (’PYTHON_PATH’, ‘path’)
for i in filepath:
filename = os.environ.get(i,”%s is null.” % i)
print ‘%s:’ % i, ‘ ‘, ‘ ‘.join(filename.split(’;'))
def arg_file(self, args):
if not args:
print ‘Error: file name is null.’
else:
if len(args) == 1 and args[0].lower() == ‘python_path’:
filename = os.environ.get(args[0], None)
if filename:
args = filename.split(’;')
else:
print ‘Error: “%s” is null’ % args[0]
exit()
for i in args:
if os.path.isfile(i):
try:
execfile(i)
except:
print ‘Error: “%s” run failed.’ % i
else:
print ‘Error: Not found “%s” file.’ % i
def arg_filetime(self, args):
if not args:
print ‘Error: file name is null.’
elif len(args) % 2 != 0:
print ‘Error: args isn’t validate’
else:
fileTimes = [i for i in args if args.index(i) % 2 != 0 ]
for i in fileTimes:
try:
fileTimes[fileTimes.index(i)] = int(i)
except Exception:
print ‘Error: time args isn’t validate’
exit()
if i <= 0:
print ‘Error: time<=0′
exit()
minTime = fileTimes[0]
for i in fileTimes:
if i < minTime:
minTime = i
strTime = time.strftime(’%Y-%m-%d-%H-%M-%S’, time.localtime())
tupleTime = tuple([int(i) for i in strTime.split('-')])
begin = datetime.datetime(tupleTime[0], tupleTime[1], tupleTime[2], tupleTime[3], tupleTime[4], tupleTime[5])
fileTimes = [[i, 0] for i in fileTimes]
seconds = 0
while True:
strTime = time.strftime(’%Y-%m-%d-%H-%M-%S’, time.localtime())
tupleTime = tuple([int(i) for i in strTime.split('-')])
end = datetime.datetime(tupleTime[0], tupleTime[1],tupleTime[2], tupleTime[3], tupleTime[4], tupleTime[5])
time_sub = end – begin
seconds = time_sub.seconds
begin = end
for i in fileTimes:
i[1] += seconds
for i in fileTimes:
if i[1] == 0:
self.arg_file( [args[args.index(str(i[0])) – 1] ] )
elif i[1] >= i[0]:
i[1] %= i[0]
self.arg_file( [args[args.index(str(i[0])) – 1] ] )
if i[0] – i[1] < minTime:
minTime = i[0] – i[1]
time.sleep(minTime)
def arg_help(self, args):
strHelp = “Usage: ps [-options] [args...] where option include:”
strHelp += “”"
-? -help print this help message
-e -environment print environment path
-en print envrionment path per row
-f -file: [file2 file3...]
execute file(.py)
-ft -filetime: [file2 time2 file3 time3...]
execute file(.py) per time,
this run not stop,
but this command hasn’t validate.
time(seconds) must is interger and
not less than zero”"”
print strHelp
def arg_args():
args_dic = {’arg_help’ : ['-?', '-help'], ‘arg_environment’ : ['-e', '-environment'],
‘arg_en’ : ['-en'], ‘arg_file’ : ['-f', '-file'], ‘arg_filetime’ : ['-ft', 'filetime']}
argsCls = ArgsDealwith()
if len(sys.argv) <= 1:
argsCls.arg_help(sys.argv)
else:
argsFun = ”
for i in sys.argv[1:]:
bMath = False
for j in args_dic.items():
if i in j[1]:
argsFun = j[0]
bMath = True
break
if bMath:
break
if argsFun:
try:
getattr(argsCls, argsFun)(sys.argv[2:])
except Exception, error:
print error
exit()
else:
print ‘Error: “%s” isn’t validate arg.’ % ‘ ‘.join(sys.argv[1:])
del argsCls
if __name__ == ‘__main__’:
arg_args()
有时我们需要在 Python 中使用 zip 文件,而在1.6版中,Python 就已经提供了 zipfile 模块可以进行这样的操作。不过 Python 中的 zipfile 模块不能处理多卷的情况,不过这种情况并不多见,因此在通常情况下已经足够使用了。下面我只是对一些基本的 zipfile 操作进行了记录,足以应付大部分的情况了。
zipfile 模块可以让你打开或写入一个 zip 文件。比如:
import zipfile
z = zipfile.ZipFile(’zipfilename’, mode=’r')
这样就打开了一个 zip 文件,如果mode为’w'或’a'则表示要写入一个 zip 文件。如果是写入,则还可以跟上第三个参数:
compression=zipfile.ZIP_DEFLATED
或
compression=zipfile.ZIP_STORED
ZIP_DEFLATED 是压缩标志,如果使用它需要编译了zlib模块。而后一个只是用zip进行打包,并不压缩。
在打开了zip文件之后就可以根据需要是读出 zip文件的内容还是将内容保存到 zip 文件中。
读出zip中的内容
很简单,zipfile 对象提供了一个read(name)的方法。name为zip文件中的一个文件入口,执行完成之后,将返回读出的内容,你把它保存到想到的文件中即可。
写 入zip文件
有两种方式,一种是直接写入一个已经存在的文件,另一种是写入一个字符串。
对于第一种使用 zipfile 对象的 write(filename, arcname, compress_type),后两个参数是可以忽略的。第一个参数是文件名,第二个参数是表示在 zip 文件中的名字,如果没有给出,表示使用与filename一样的名字。compress_type是压缩标志,它可以覆盖创建 zipfile 时的参数。第二种是使用 zipfile 对象的 writestr(zinfo_or_arcname, bytes),第一个参数是 zipinfo 对象或写到压缩文件中的压缩名,第二个参数是字符串。使用这个方法可以动态的组织文件的内容。
需要注意的是在读出时,因为只能读出内容, 因此如果想实现按目录结构展开 zip 文件的话,这些操作需要自已来完成,比如创建目录,创建文件并写入。而写入时,则可以根据需要动态组织在 zip 文件中的目录结构,这样可以不按照原来的目录结构来生成 zip 文件。
于是我为了方便使用,创建了自已的一个 ZFile 类,主要是实现象 winrar 的右键菜单中的压缩到的功能–即将一个zip文件压缩到指定目录,自动创建相应的子目录。再有就是方便生成 zip 文件。类源码为:
import zipfile
import os.path
import osclass ZFile(object):
def __init__(self, filename, mode=’r', basedir=”):
self.filename = filename
self.mode = mode
if self.mode in (’w', ‘a’):
self.zfile = zipfile.ZipFile(filename, self.mode, compression=zipfile.ZIP_DEFLATED)
else:
self.zfile = zipfile.ZipFile(filename, self.mode)
self.basedir = basedir
if not self.basedir:
self.basedir = os.path.dirname(filename)def addfile(self, path, arcname=None):
path = path.replace(’\\’, ‘/’)
if not arcname:
if path.startswith(self.basedir):
arcname = path[len(self.basedir):]
else:
arcname = ”
self.zfile.write(path, arcname)def addfiles(self, paths):
for path in paths:
if isinstance(path, tuple):
self.addfile(*path)
else:
self.addfile(path)def close(self):
self.zfile.close()def extract_to(self, path):
for p in self.zfile.namelist():
self.extract(p, path)def extract(self, filename, path):
if not filename.endswith(’/'):
f = os.path.join(path, filename)
dir = os.path.dirname(f)
if not os.path.exists(dir):
os.makedirs(dir)
file(f, ‘wb’).write(self.zfile.read(filename))def create(zfile, files):
z = ZFile(zfile, ‘w’)
z.addfiles(files)
z.close()def extract(zfile, path):
z = ZFile(zfile)
z.extract_to(path)
z.close()
这个 zfile.py 模块提供了两个方法:create和extract,还有一个 ZFile 的类。create和extract用来创建和解压 zip 文件。
create需要两个参数,第一个为要生成的zip文件名,第二个为一 个文件列表,它是一个list变量,每一项或者是一个字符串文件名,或者是一个tuple,第一个为文件名,第二个为在压缩文件中的名字,可以有路径, 如:
['d:/a.csv', 'd:/test/a.JPG', ('d:/test/mixin/main.py', 'main.py')]
那 么对于文件名有以下的处理,如果文件列表中的文件名与压缩文件名的路径相同,则在压缩文件中会自动变成相对路径。比如上面的文件列表,如果压缩文件为:
d:/aaaa.zip
则 在压缩文件中的压缩文件名最终为:
['a.csv', 'test/a.JPG', 'main.py']
那么最后一个因为指定了在压缩文件中的名字,因此使用指定 的名字。
extrace需要两个参数,第一个为压缩文件名,第二个为解压到的路径名。
这两个方法都使用了 ZFile 类。ZFile 类则提供了一些更底层些的类。它的构造函数可以根据mode的值来选择是打开还是写入。另外如果还想做更底层的控制,可以通过 ZFile 实例得到 zfile 属性,它是一个 ZipFile 模块实例,可以直接使用。
<%@ LANGUAGE = Python %>
把vbscript和jscriptT了,用Python脚本。真另类 吧.
在ASP中使用Python脚本:
1.首先安装好Active Python,它自带了win32扩展,省得自己装了;
2. 按照Active的附带文档说明,在%Python_home%/lib/site_packages/win32comext/axscript /client/目录中找到pyscript.py,双击运行之,此步骤在IIS中安装Python解释引擎;
3.新建一个asp文件,文件头 用<%@ LANGUAGE = Python %>,告诉IIS此文件采用Python脚本;
4.剩下的就是按python语法 编程了。
5.例子:访问Access:
<%@ LANGUAGE = Python %>
<!–#include file=”pyDB4Jet.asp”–>
<%
#创建数据访问类的实例
myax=Cdb4Jet()
调 用数据访问类的查询方法,返回结果赋给rs
rs=myax.query(’select * from [user]‘)
#以下这段 注掉的代码用来遍历打印取回来数据的字段
#flds_dict={}
#for x in range(rs.Fields.Count):
# flds_dict[x]=rs.Fields.Item(x).Name
# Response.write(flds_dict[x] + “<br>”)
#遍历取回来的数据
while not myax.rs.EOF:
#把每行的第三个字段值输出(字段序号从0开始)
Response.write(rs.Fields[2].Value+”<BR>”)
#移动到下一行
myax.rs.MoveNext()
#重新移回第一行
myax.rs.MoveFirst()
#再次遍历
while not myax.rs.EOF:
#输出每行的第二个字段值
Response.write(rs.Fields[1].Value+”<br>”)
#移动到下一行
myax.rs.MoveNext()
%>
比较遗憾的是在Python中访问 Recordset时我不知道怎么用字段名,只会用字段序号。
另外一个要注意的是访问access的表时必须用“[]”括起来。
6. 上例中用到的access访问类:
<%
# -*-coding:UTF-8-*- #这一句告诉python用UTF-8编码
#=================================================================
# NAME: pyDB4Jet
# AUTHOR: benyur
# DATE : 2004-12-30
# COMMENT: Python的ACCESS访问模块
#=================================================================
#导入win32com模块
import win32com
#数据访问类定义
class Cdb4Jet:
# 构造函数,python的构造函数不同于C++/C#或Java的构造函数,在执行到__init__方法时,实例已经存在
def __init__(self):
#win32com.client.Dispatch用于创建COM对象
#创建ADO的 Connection数据连接对象
self.conn=win32com.client.Dispatch(r’ADODB.Connection’)
#DSN保存数据库的访问连接串
self.DSN=’PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=E:\wwwroot\csip\#news.mdb;’
#打开数据库
self.conn.Open(self.DSN)
#创建ADO的Recordset数据集对象
self.rs=win32com.client.Dispatch(r’ADODB.Recordset’)
#定义查询方法
def query(self,sql):
#执行Recordset对象的Open方法,从数据库取回数据 集
self.rs.Open(sql,self.conn,1,1)
#返回数据集给调用者
return self.rs
# 定义非查询方法
def execute(self,sql):
#直接调用Connection对象的execute方法执行sql语 句,并把执行结果返回给调用者
return self.conn.execute(sql)
%>
David Mertz 创作的 可爱的 Python的第一、第二部分概述了在 Python 中使用XML。然而,在那些最初的文章出现后,Python 中的 XML工具有了很大的发展。不幸的是,这些改进中的大多数并不向后兼容。在这个特别部分中,重温了作者先前对XML 工具的讨论,并提供最新的代码示例。
在 许多情况下,Python 是使用 XML 文档的理想语言。像 Perl、REBOL、REXX 和 TCL 一样,它是一种灵活的脚本语言,并且有强大的文本操作能力。而且,除了对多数类型的文本文件(或流文件)编码外,XML 文档还编码大量复杂的数据结构。
继 续在 Python 2.0 中对 XML 的支持
文本处理中常见的“读取几行,并将它们与一些规则表达式比较”样式通常不能很好地适合对 XML 进行彻底语法分析和处理。幸好,Python(与大多数其它语言相比)不仅有处理复杂数据结构的直接方法(通常使用类和属性),还有一系列 XML 相关的模块可以帮助语法分析、处理和生成 XML。
XML-SIG (专门兴趣组)的成员为维护 Python 一系列 XML 工具做了许多工作。与其它 Python 专门兴趣组一样,XML-SIG 要维护邮件发送列表、列表档案、有用的参考大全、文档、标准包和其它资源(请参阅本文后的 参考资料)。
从 Python 2.0 开始,Python 在其标准发行版中包括大多数 XML-SIG 项目。最新的 XML-SIG 包可能包含一些 Python 标准发行版中没有的“极端先进”特性,但出于面向绝大多数人的目的 — 包括本文中的讨论 — Python 2.0 的 XML 支持将是您感兴趣的。幸运的是,早期 Python 版本对 xmllib 的基本支持在 Python 2.0+ 下有了很大进步。目前,Python 用户能正常的选择 DOM 、 SAX 和 expat 技术来处理 XML (使用其他编程语言的 XML 开发人员将会意识到这些)。
模 块:xmllib
xmllib 是一个非验证的低级语法分析器。应用程序员使用的 xmllib 可以覆盖 XMLParser 类,并提供处理文档元素(如特定或类属标记,或字符实体)的方法。从 Python 1.5x 到 Python 2.0+ 以来, xmllib 的使用方法并没变化;在绝大多数情况下更好的选择是使用 SAX 技术,它也是种面向流的技术,对语言和开发者来说更为标准。
本文中的 示例与原来专栏中的相同:包括一个叫做 quotations.dtd 的 DTD 以及这个 DTD 的文档 sample.xml (请参阅 参考资料,以获取本文中提到的文件的档案)。以下的代码显示了 sample.xml 中每段引言的前几行,并生成了非常简单的未知标记和实体的 ASCII 指示符。经过分析的文本作为连续流来处理,所使用的任何累加器都由程序员负责(如标记中的字符串 (#PCDATA),或所遇到的标记的列表或词典)。
清单 1: try_xmllib.pyimport
xmllib, string
class
QuotationParser
(xmllib.XMLParser):
"""Crude xmllib extractor for quotations.dtd document"""
__init__
(self):
xmllib.XMLParser.__init__(self)
self.thisquote = '' # quotation accumulator
def
handle_data
(self, data):
self.thisquote = self.thisquote + data
syntax_error
(self, message):
pass
def
start_quotations
(self, attrs): # top level tag
print
'--- Begin Document ---'
start_quotation
(self, attrs):
print
'QUOTATION:'
end_quotation
(self):
print
string.join(string.split(self.thisquote[:230]))+'...',
print
'('+str(len(self.thisquote))+' bytes)
'
self.thisquote = ''
unknown_starttag
(self, tag, attrs):
self.thisquote = self.thisquote + '{'
unknown_endtag
(self, tag):
self.thisquote = self.thisquote + '}'
unknown_charref
(self, ref):
self.thisquote = self.thisquote + '?'
unknown_entityref
(self, ref):
self.thisquote = self.thisquote + '#'
if
__name__ == '__main__':
parser = QuotationParser()
for
c
in
open("sample.xml").read():
parser.feed(c)
parser.close()
模块:xmllib
xmllib 是一个非验证的低级语法分析器。应用程序员使用的 xmllib 可以覆盖 XMLParser 类,并提供处理文档元素(如特定或类属标记,或字符实体)的方法。从 Python 1.5x 到 Python 2.0+ 以来, xmllib 的使用方法并没变化;在绝大多数情况下更好的选择是使用 SAX 技术,它也是种面向流的技术,对语言和开发者来说更为标准。
本文中的 示例与原来专栏中的相同:包括一个叫做 quotations.dtd 的 DTD 以及这个 DTD 的文档 sample.xml (请参阅 参考资料,以获取本文中提到的文件的档案)。以下的代码显示了 sample.xml 中每段引言的前几行,并生成了非常简单的未知标记和实体的 ASCII 指示符。经过分析的文本作为连续流来处理,所使用的任何累加器都由程序员负责(如标记中的字符串 (#PCDATA),或所遇到的标记的列表或词典)。
清单 1: try_xmllib.pyimport
xmllib, string
class
QuotationParser
(xmllib.XMLParser):
"""Crude xmllib extractor for quotations.dtd document"""
__init__
(self):
xmllib.XMLParser.__init__(self)
self.thisquote = '' # quotation accumulator
def
handle_data
(self, data):
self.thisquote = self.thisquote + data
syntax_error
(self, message):
pass
def
start_quotations
(self, attrs): # top level tag
print
'--- Begin Document ---'
start_quotation
(self, attrs):
print
'QUOTATION:'
end_quotation
(self):
print
string.join(string.split(self.thisquote[:230]))+'...',
print
'('+str(len(self.thisquote))+' bytes)
'
self.thisquote = ''
unknown_starttag
(self, tag, attrs):
self.thisquote = self.thisquote + '{'
unknown_endtag
(self, tag):
self.thisquote = self.thisquote + '}'
unknown_charref
(self, ref):
self.thisquote = self.thisquote + '?'
unknown_entityref
(self, ref):
self.thisquote = self.thisquote + '#'
if
__name__ == '__main__':
parser = QuotationParser()
for
c
in
open("sample.xml").read():
parser.feed(c)
parser.close()
SAX (XML 的简单 API)是 XML 语法分析器的公用语法分析器接口。它允许应用程序作者编写使用 XML 语法分析器的应用程序,但是它却独立于所使用的语法分析器。(将它看作 XML 的 JDBC。)(Lars Marius Garshol,SAX for Python)
SAX — 如同它提供的语法分析器模块的 API — 基本上是一个 XML 文档的顺序处理器。使用它的方法与 xmllib 示例极其相似,但更加抽象。应用程序员将定义一个 handler 类,而不是语法分析器类,该 handler 类能注册到任何所使用的语法分析器中。必须定义 4 个 SAX 接口(每个接口都有几个方法):DocumentHandler、DTDHandler、EntityResolver 和 ErrorHandler。创建语法分析器除非被覆盖,否则它还连接默认接口。这些代码执行与 xmllib 示例相同的任务:
清单 3: try_sax.py
"Simple SAX example, updated for Python 2.0+"
import
string
import
xml.sax
from
xml.sax.handler
import
*
class
QuotationHandler
(ContentHandler):
"""Crude extractor for quotations.dtd compliant XML document"""
__init__
(self):
self.in_quote = 0
self.thisquote = ''
startDocument
(self):
print
'--- Begin Document ---'
startElement
(self, name, attrs):
if
name == 'quotation':
print
'QUOTATION:'
self.in_quote = 1
else:
self.thisquote = self.thisquote + '{'
endElement
(self, name):
if
name == 'quotation':
print
string.join(string.split(self.thisquote[:230]))+'...',
print
'('+str(len(self.thisquote))+' bytes)
'
self.thisquote = ''
self.in_quote = 0
else:
self.thisquote = self.thisquote + '}'
characters
(self, ch):
if
self.in_quote:
self.thisquote = self.thisquote + ch
if
__name__ == '__main__':
parser = xml.sax.make_parser()
handler = QuotationHandler()
parser.setContentHandler(handler)
parser.parse("sample.xml")
与 xmllib 相比,上述示例中要注意两件小事: .parse() 方法处理整个流或字符串,所以不必为语法分析器创建循环; .parse() 同样能灵活地接收一个文件名、一个文件对象,或是众多的类文件对象(一些具有 .read() 方式)。
包:DOM
DOM 是一种 XML 文档的高级树型表示。该模型并非只针对 Python,而是一种普通 XML 模型(请参阅 参考资料以获取进一步信息)。Python 的 DOM 包是基于 SAX 构建的,并且包括在 Python 2.0 的标准 XML 支持里。由于篇幅所限,没有将代码示例加到本文中,但在 XML-SIG 的 “Python/XML HOWTO” 中给出了一个极好的总体描述:
文 档对象模型为 XML 文档指定了树型表示。顶级文档实例是树的根,它只有一个子代,即顶级元素实例;这个元素有表示内容和子元素的子节点,他们也可以有子代,以此类推。定义的 函数允许随意遍历结果树,访问元素和属性值,插入和删除节点,以及将树转换回 XML。DOM 可以用于修改 XML 文档,因为可以创建一棵 DOM 树,通过添加新节点和来回移动子树来修改这棵树,然后生成一个新的 XML 文档作为输出。您也可以自己构造一棵 DOM 树,然后将它转换成 XML;用这种方法生成 XML 输出比仅将 <tag1>…</tag1> 写入文件的方法更灵活。
使用 xml.dom 模块的语法与早期的文章相比有了一些变动。Python 2.0 中自带的 DOM 实现被称为 xml.dom.minidom ,并提供轻量级和小型版本的 DOM。显然,完整的 XML-SIG 的 DOM 中有些试验性的特性并未被放入 xml.dom.minidom 中,但大家并不会注意到这一点。
生成 DOM 对象很简单;只需:
清单 4: 在 XML 文件中创建 Python DOM 对象
from
xml.dom.minidom
import
parse, parseString
dom1 = parse('mydata.xml') # parse an XML file by name
使用 DOM 对象是种非常直接的 OOP 模式的工作。然而,经常在无法立刻简单区分的层级(除了循环列举)中碰到许多类似清单的属性。例如,以下是一段普通的 DOM Python 代码片断:
清 单 5: 通过 Python DOM 节点对象的迭代
for
node
in
dom_node.childNodes:
if
node.nodeName == '#text': # PCDATA is a kind of node,
PCDATA = node.nodeValue # but not a new subtag
elif
node.nodeName == 'spam':
spam_node_list.append(node) # Create list of <spam> nodes
Python 标准说明文档中有一些更详细的 DOM 示例。我的早期文章中有关使用 DOM 对象的示例(请参阅 参考资料)指出的方向仍然是正确的,但是文章发布后至今,一些方法和属性名称以更改,因此请查阅一下 Python 的说明文档。
模块: pyxie
pyxie 模块是在 Python 标准 XML 支持之上构建的,它为 XML 文档提供了附加的高级接口。 pyxie 将完成两项基本操作:它将 XML 文档转换成一种更易于进行语法分析的基于行的格式;并且它提供了将 XML 文档当作可操作树处理的方法。 pyxie 所使用的基于行的 PYX 格式是不受语言限制的,其工具适用于几种语言。总之,文档的 PYX 表示与其 XML 表示相比,更易于使用常见的基于行的文本处理工具进行处理,如 grep、sed、awk、bash、perl,或标准 python 模块,如 string 和 re 。根据结果,从 XML 转换到 PYX 可能节省许多工作。
pyxie 将 XML 文档当作树处理的概念与 DOM 中的思路相似。由于 DOM 标准得到许多编程语言的广泛支持,那么如果 XML 文档的树型表示是必需的,大多数程序员会使用 DOM 标准而非 pyxie 。
更多模块: xml_pickle 和 xml_objectify
我自行开发了处理 XML 的高级模块,称为 xml_pickle 和 xml_objectify 。我还在其它地方写过许多类似模块(请参阅 参考资料),在此不必做过多的介绍。当你“用 Python 思考”而不是“用 XML 思考”时,这些模块非常有用。特别是 xml_objectify 自身对程序员隐藏了几乎所有的 XML 线索,使您在程序中充分使用 Python “原始”对象。实际的 XML 数据格式几乎被抽象得不可见。同样, xml_pickle 使 Python 程序员以“原始” Python 对象开始,该对象的数据可以来源于任何源代码,然后把它们(连续地)放入其他用户以后可能需要的 XML 格式。
我先给一个初步的表格吧,大家如果有什么意见,或有补充,欢迎提出。有些我没有用过,先不写了。
以下是我使用过的python IDE:

除了PythonWin, VisualPython只支持Windows,其它都至少支持Win/Linux/Mac。
各项含义:
自动补全:变量/函数名打到一半 时,提示可能的完整的变量/函数名。
智能感知:在库/类/对象后打”.”后,提示可能的函数或变量。
调试:分四档,从好用到不好用分别为 “类VC”(调试器操作方式与VC/eclipse相似),“WPDB”(使用WinPdb作为调试器),“用库”(要配合专门的python调试库,即 要改代码来配合调试),最惨的当然是“无”啦。
语法检查:从好用到不好用分别为“存盘时”(存盘时自动检查,也可以在菜单里手动选择检查),“手 动”(在菜单里选择检查),“无”(没有语法检查功能)
开源:分为开源,共享(提供免费试用,然后需要付费),收费三种。目前还没有“收费”这一 类。
推荐度:五星为最推荐,一星为最不推荐。推荐度为作者主观评价,不代表其他人意见。
各IDE简介(注意本文最后修改时间是 2008年7月):
IDLE:
装了python就会有这个,大家肯定都用过了,功能还凑合,调试器的 使用方法和大家熟悉的eclipse/Visual Studio很不一样,需要学习和适应。各项表现都一般。推荐度:★★
PythonWin:
内 置Win32 extension,PythonWin成为了win32的python程序开发者必备的工具。虽然它只能运行在Win下,但其实也是开源的。功能上可以 认为它是加上了自动补全和智能感知功能的IDLE,虽然和以其它一些复杂的IDE相比有些差距,但却是轻量级Python IDE的首选。推荐度★★★
SPE:
全 名Stani’s Python Editor。相当不错的IDE,语法高亮、代码折叠、智能感知、自动语法检查等功能一应俱全,集成wxGlade。可惜没有自动补全功能。开源,可以用 svn下载到最新的源代码,依赖wxPython。推荐度★★★★★
附:总有人说下不到SPE,去这里看看:
http://developer.berlios.de/project/showfiles.php?group_id=4161
SVN 方式下载:
http://pythonide.blogspot.com/2007/02/how-to-download-latest-spe-from_26.html
Ulipad:
前 身是NewEdit,和SPE相比,多了自动补全功能,因而比SPE更加方便,不过没有把界面设计器wxGlade集成进来。开源,可以用svn下载到最 新的源代码,依赖wxPython。推荐度★★★★★。
Eric:
Eric 升级到4后,各方面有了很强的提升,全方位超过其它开源IDE。使用PyQt4作为图形库,界面美观大方,并与QtDesigner结合,使得开发GUI 程序变得非常方便,比下面将提到到BOA还要好用。最大的亮点莫过于它的调试器,支持断点设置、单步调试和变量值查看。一句话,有了Eric4,就不用再 去捣腾商业的IDE了。推荐度★★★★★,个人强烈推荐。
Eric4在Windows下的安装有些要注意的地方,参见:
http://hi.baidu.com/runningon/blog/item/091dd009c4c80187d1581b05.html
Boa Constructor:
比起SPE和Ulipad,BOA的编辑功能相当单薄,自动补全与智能感知都要手动,而且没有自动语法检查,但调试器 相当好用。最大的亮点是界面设计器相当好用,比wxGlade要好用得多。硬伤是对中文支持不好。依赖wxPython。推荐度★★★。
WingIDE:
很 不错的商业软件,调试器是类VC/eclipse的,相当好用,而且还支持project组织。但默认的设置是不支持中文的,要设置一下字体。不开源,而 且破解不好找。既然已经有了好用的开源软件了,又何必再用盗版的呢?推荐度★★★★
Komodo:
由 ActiveState公司制作,该公司的ActivePython和ActivePerl可是相当有名。Komodo和WingIDE一样也是很不错的 商业软件,可以说WingIDE有的大部分优点Komodo也有,非常可惜没有自动补全。还支持宏录制(类似MS Office的宏录制),不过这也只是个噱头。不爽之处在于相当耗资源,我AMD 64位双核+1G内存+5400转的硬盘的本本,启动它时硬盘闪了足足一分钟。400$的价格对它来讲贵了点。推荐度★★★★
VIM/emacs + 插件:
Linux我也玩了好几年了,平心而论这两个东东不适合初学(的开发)者。现在Linux已经比较好用了,不会 vim/emacs也不是什么大不了的事了,特别是后者。推荐度★★★。
eclipse + pydev:
依 靠强大的eclipse,pydev显得格外耀眼。强大的调试功能和舒服的编辑环境让pydev赢得了许多人的青睐。不过eclipse本来就是耗资源大 户,pydev在这一点上毫无办法。能配好pydev需要一些人品,用最新的eclipse,在线安装最新pydev(pydev的网站上会有介绍),成 功率会高一些。推荐度★★★★
VisualStudio.Net 2003 + VisualPython:
已 经停止维护了,烂就一个字,多说无益,基本不能用。推荐度★
在与Sun微系统公司合并之后,甲骨文将停 止继续访问Sun开发的开源软件项 目托管网站Project Kenai。
甲骨文星期二在更新的开发人员常见问题解答声明中说,Kenai网站将停止公开使 用。甲骨文将继续在内部使用这个网站并且寻求一些让我们的客户利用这个网站的方法。
Project Kenai团队在网站上发表的有关这个网站的前途的公告中说,目前正在逐步取消这个网站以便整合这个项目托管网站。减少当前项目托管网站的数量是朝着这个 方向发展的开始。
在 Kenai测试版网站,用户被告知要把资料库和 内容转移到其它地方。
Kenai团队说,这个网站的完全关闭和删除这个域名将在未来的60天内完成(2010年4月2 日)。这为所有的项目迁移到项目拥有者选择的新家提供了充裕的时间。在60天期限(2010年4月2日)之后,任何留在该网站的项目都将被删除,这个网站 将关闭。
Kenai团队说,虽然关闭Kenai.com域名的时间不远了,但是,这个基 础设施将来会继续存在以支持其它的域名。 Netbeans.org已经在使用这个基础设施。
甲骨文还 在常见问题解答中宣布要把甲骨文技术网络、Sun BigAdmin系统管理门户网站和包括java.sun.com网站在内的Sun开发人员网站合并在一起。甲骨文说,这个合并将产生最大的和种类最多的 开发人员、数据库管理 员、系统管理员和设计师的社区。
甲骨文说,在最近的将来,Sun开发人 员网络和BigAdmin网站将保持现状。甲骨文预计这些网站将集成为一个重新设计的甲骨文技术网络。