按:曾在2006年发表于公司内部刊物,有删节。 零敲碎打 --- Python新手不完全FAQ 如果''国家的正义在于三种人各司其职''(《理想国》-- 柏拉图),那么对程序员来说,编码的正义或许就在于各种语言各司其职。掌握一门脚本语言对提高我们的工作效率和质量是有很大帮助的,这里向大家严重推荐Python语言。 本文是笔者在学习和使用Python时所做笔记的整理,希望这篇FAQ能够节省大家学习Python的时间和精力,同时希望Python能够给大家的工作和生活带来更高的效率。 关于 1.1 什么是Python? Python 是一门语法简洁优美,面向对象,内置高级数据结构,支持模块和包,支持多种平台,可扩展的解释型通用编程语言。 安装好Python之后,交互环境下输入: >>>import this 可以看到一段Python自己的哲学。 1.2 如何开始学习Python? 建议的学习流程: 基本流程控制语句->类,函数的写法->内置高级数据类型(列表,元组,字典,串)->根据需要学习标准库中的模块或者其他模块/架构 调试 2.1 如何调试我的Python脚本? 你需要标准库中的pdb模块。 只需在代码中加入: ... import pdb # 引入pdb模块 ... pdb.set_trace() # 在需要设断点的地方加入这句~ ... 如此这般,程序运行至断点出会停住。然后,如果熟悉GDB那么一切都好办了,如果不熟悉,请学习GDB~,因为pdb的调试命令基本都是模仿GDB的,看名字就知道了^^。 文件 3.1 如何拷贝/移动文件? 有几种方法可以做到这件事,最简单的是使用shutil模块: import shutil # 引入shutil模块 shutil.copyfile('./a.txt','../xx/b.txt') # 拷贝文件 shutil.move('../build/a.txt','./debug/') # 移动文件 3.2 如何遍历目录? os模块中有两个函数可以方便的遍历目录: os.walk(top, dirs, fnames) 其中: top 为当前目录相对路径 dirs 列表,保存当前目录下所有子目录名 fnames 列表,当前目录下所有文件名 os.path.walk(top, func, arg) 其中: top 所要遍历的目录名 func 回调函数,格式为 func(arg, dirname, fnames) arg 回调函数参数,如果不需要其他的参数,就传个None好了 3.3 如何作文件/串压缩? zlib模块和gzip模块正是你所需要的。 zlib.compress(str) # 压缩字符串str,返回压缩后的串 zlib.decompress(str) # 上面函数的反函数 gzip.zlib.compress(str) # 算法不同,其余同上~ gzip.zlib.decompress(str) 如果需要对文件压缩/解压,需要使用 zipfile 模块,tgz格式的文件需要配合tarfile模块。 3.4 如何查看串的16进制值? 使用binascii模块 binascii.b2a_hex(str) # 返回一个串中每个字节的16进制ASCII值 binascii.a2b_hex(str) # 以上的反函数,给出一串16进制值,返回相应的字符串 3.5 如何获得文件信息? os.stat(fname) # 返回文件时间,大小,所在驱动器等信息 3.6 如何作文件映射? 使用标准库中的mmap模块。 import mmap mmap.mmap(fn, size) # fn 为文件号,size为buffer大小,返回映射后的buffer 例: import mmap import os fi = open('./tmp.dat', 'r+') # 注意,打开方式为读写 c = mmap.mmap(fi.fileno(), os.stat(fi.name).st_size) # 映射 print c.readline() # 映射的buffer与普通文件操作方法是相同的 StringIO模块,兴许你也会感兴趣。可以利用这个模块在内存中虚拟一个文件。 例: import StringIO # 引入所需模块 f = StringIO.StringIO() # 建立一个虚拟文件 f.write('hello, python') # 与普通文件的操作方法是相同的 f.seek(0) print f.read() 由于是保存在内存中,所以程序退出后就不存在了,需要的话别忘了向磁盘写一份~ 编码 4.1 为什么要讨论编码问题? 有人抱怨 Python 对中文的支持不好,实际上是在使用中忽略了编码的问题。许多库函数默认的编码是Unicode,而标准输入输出环境或者脚本的源码是由都不是 Unicode ,如此,使用的时候就会发现一堆乱码出现在命令行或者窗体上...实际上Python对于各种编码的处理是很出色的,我们只需要简单了解一下。 4.2 如何获得当前标准输入输出的编码? 通过sys模块的如下两个属性 sys.stdout.encoding sys.stdin.encoding 通常,中文Windows下面得到的结果是cp936。 4.3 如何将串的编码转换到我需要的编码? 先转换为unicode,再转换为具体的编码,因为Python内部的编码是Unicode。 字符串类型的量有两个函数: str.decode(encoding) # 将字符串的内容按指定编码解码 str.encode(encoding) # 将字符串的内容按指定编码编码 例: >>>mystr = 'Hello, 世界~' # 以Windows为例,此时mystr的编码为'cp936' >>>mystr.decode('cp936') # mystr 的内容按 'cp936' 解码的结果,以 Unicode 形式返回。 u'Hello, \u4e16\u754c\uff5e' >>>mystr.encode('utf8') # mystr 的内容按 'utf8' 编码,结果自然以 'utf8' 形式返回 -___-。 注意: 1.写文件时不可以用 unicode,要声明一种编码如 utf8/big5/gbk... 2.utf 系列编码可以包容简繁,但是,简繁之间不能通过 utf 为中介字字转换,因为同一个字的简繁体对应的是 utf 中不同的编码,不知说清楚了没 - -~! 4.4 脚本原文件的编码如何指定呢? 只要在文件开头第二行注释中声明一下就行了。 官方文档中是这样说地: More precisely, the first or second line must match the regular expression "coding[:=]\s*([-\w.]+)". 因此通过上述的正则表达式就可以知道: coding后面为:或=均可。根据上面的正则式可以推出几种正确的写法,找一种喜欢的吧。 coding:cp936 coding=cp936 至于前面有什么都无所谓。 例: #!/usr/bin/python # coding=utf8 ... 标准输入输出 5.1 在屏幕上输出数据 import sys def pyout(str): sys.stdout.write(str) sys.stdout.flush() >>>pyout(something) >>>pyout('\r') # 清除标准输出的当前行 当然,也可以用简单的 print... 5.2 怀念 C 中的格式化输出? 字符串配合%符。 例: >>>'%s %o %x %%'%('test', 16, 16) 'test 20 10 %' 5.3 得到命令的结果 #得到控制台程序输出 import os c = os.popen("dir").read() #得到窗口程序的标准输出 import commands x = commands.getoutput('ls') 语法杂技 6.1 怎样显式释放内存,如何防止内存泄露? 嗯,请相信Python的内存回收机制,您大可以发挥一下主观能动性,构造一个(您认为)会产生内存泄露的程序,观察一下结果是否和设想相同。 实际上当一个引用不再需要时,只要 del 掉即可。 对于像笔者这样每次走出家门100米开外都要回来查看一下是否锁了门的强迫症疑似者,请使用gc模块。 import gc ... gc.collect() # 返回所有被清除的unreachable对象个数。 6.2 怎样复制可以得到一个对象的全部内容,而不仅仅是其引用? 使用 copy 模块。 copy.deepcopy(...) # 返回目标对象的全部内容 6.3 列表生成式 提一下,这个语法太方便了,详细请参考官方文档。 例: a = range(10) # 生成数字 0~9 列表 a = [i**2 for i in a if i % 2 == 0] # 这下a变成9以内偶数平方的列表了。 6.4 内建函数 dir() # 列出对象方法和属性 help() # 列出对象的说明文档 del # 删除对象引用 type() # 对象类型 id() # 对象的唯一标识 6.5 内建常数 None # 类似 C++ 中的 null True # 注意大小写! False # 同上~ 6.6 一行之内已经难以容纳我的一句代码了~! 如果您希望在一行之中写多句代码,请使用';'号。(众读者:歹人...) 如果希望使用多行写一句代码,请使用续行符'\'或者括号。 续行符和括号的例子: # 下面是一句比较长的代码 a = ''.join([chr(ord(i) - 2) for i in '|jg|jqpiokocvcklkcpfcpng000']) # 下面这两行是加了续行符的。 # 注意,续行符后除了回车不能接任何字符,不要在续行符后写注释。 a = ''.join([chr(ord(i) - 2) for i in '|jg|jqpioko\ cvcklkcpfcpng000']) # 下面两行是使用括号续行的,续多少行都行,同样不要在断行处写注释 # 凡是圆括号()、方括号[]、花括号{}及三引号字符串内的部分均不需要使用续行符。 a = ''.join([chr(ord( i) - 2) for i in '|jg|jqpiokocvcklkcpfcpng000']) 推荐工具 pysh,*nix下面有csh,Python爱好者有跨平台的pysh。pysh是Python编写的shell,兼容*nix shell操作方式,并且可以方便的以交互方式编写python脚本。现在我已经基本上用pysh取代cmd和sh了...这种感觉真好,我命苦的小拇指终于得到解脱了~~。 ctags,python模块,已被加入Python2.5的标准库。这个模块提供了Python在Linux和Windows平台下调用动态链接库的能力...想象一下吧,如果你的程序同时具有C++的运行效率和Python的开发效率...>_< 最后 限于篇幅,本文到此为止,希望大家了解脚本,学习脚本,让我们的工作更有效率,让我们的生命更有意义! ( 另: 如果坚持/习惯在写给自己用的工具的时候,用C/C++写遍历目录的代码,您是老张;如果公共目录下有一堆Python书籍,您是David;如果问怎么把.py的文件编译成.exe的,您是童童;如果觉得'END'比'\t'优雅,您是桑哥;如果觉得Python其实是'密林',您是阿楠; 鉴定完毕,欢迎拍砖! )