| Python FAQ4 |
用户设定 |
| ChinesePython Wiki | 中蟒大杂院 | 最近修改 | 标题目录 | 看发表区 | 搜寻/发表 | 站内导航 | 求助 |
Pythonwin 有它自己一个图形接口的除错工具,是建基于 bdb 上的。 它有彩色的断点显示和其个挺不错的功能 (包括帮非 Pythonwin 的程序除错). 尽管它的接口还有需要改进的地方, 但它无疑是非常有趣的产品. 使用方法可参考 Pythonwin 自带的档: http://www.python.org/ftp/python/pythonwin/pwindex.html
在 ActivePython 中带有最新的 Pythonwin 版本: http://www.activestate.com/Products/ActivePython/index.html
Richard Wolff 写了一个改良版的 pdb, 叫做 Pydb. 它是和流行的 Data Display Debugger (DDD) 配合来用的. Pydb 在 http://daikon.tuc.noao.edu/pythyon/ , 而 DDD 则位于 http://www.cs.tu-bs.edu.softech/ddd/
Python 本身的 IDLE 编程环境中也有一个图形接口的除错器. 一般的下载版本中它位于 Tools/idle 目录中.
Python2.0 以前只能用 plain curses; ncurses 的一些特殊功能如颜色等不能用.(虽然这个模组其实是使用 ncurses)
Python2.0 开始, 引入 Oliver Andrich 的新版本, curses 模组功能增强很多. 从 ncurses 和 SYSV curses 中引进了象颜色, 字符集, 鼠標等的支援. 这代表光有 BSD curses 的系统已不可使用这个模组了, 不过好象已没有任何"活"的系统还属于这个类别了.
== 4.4 在 Python 中有没有和 C 语言的 onexit() 相对应函数 ? 版本 2.0: 新加的 atexit 模姐提供了和 onexit 相似的功能. 详情请参阅函数库的参考手册. 在 2.0 版本中你不应该像 1.5.2 版那样覆写一个新的 sys.exitfunc !
版本 1.5.2: 你需要加载 sys 模块并且覆写一个新的 sys.exitfunc 函数. 这个函数会当程序正常终止, 因遇到无法处理的异常而退出, 或是在 UNIX 系统下接收到 SIGNTERM 或 SIGHUP 讯号.
list.reverse()
try:
for x in list:
"干活"
finally:
list.reverse()
不过这个方法不好的地方是,在你"干活"的过程中, list 被反过来了. 如果你不喜欢, 你也可以复制一份. 唯然看起来浪费时间来复制列表, 但其实它比下面的方法都要快.
如果序列并非列表, 上面有一个更普遍但较慢的方法:
for i in range(len(sequence)-1, -1, -1): x = sequence[i] <do something with x>
还有个更优雅的解决方案: 定义一个序列类, 它会接收要反序的序列然后从末端逐一给出序列中的内容(方案由 Steve Majewski 提出):
class Rev: def __init__(self, seq): self.forw = seq def __len__(self): return len(self.forw) def __getitem__(self, i): return self.forw[-(i + 1)]
用起来很简单:
for x in Rev(list): <do something with x>可惜的是, 这个办法是所有方法中最慢的, 因为调用类的方法需要一定的时间...
因为效率和归一上的考虑, Python 只会在模块第一次被加载时读取在磁盘上的相关模块文件. (想象一个程序有后多个模块, 而每个模块又会加载相同的一个共享模块, 如果每次都读一次档案的话会很耗资源. 如果你要强迫 Python 重新去磁盘上去加载模块, 可以这样:
import modname ... 干点什么 reload(modname)声明: 这方法并不是百分之百绝对可行的. 特别是像下面那样:
from modname import some_objects如此的话, 无论你怎样 reload, 那些载入的类呀什么的依然是第一次载入的样子.
小于 1000 的质数 print filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0, map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))
开头 10 个 Fibonacci 数 print map(lambda x,f=lambda x,f:(x<=1) or (f(x-1,f)+f(x-2,f)): f(x,f), range(10))
Mandelbrot 集 print (lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y, Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM, Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro, i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y >=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr( 64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy ))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24) # \___ ___/ \___ ___/ | | |__ lines on screen # V V | |______ columns on screen # | | |__________ maximum of "iterations" # | |_________________ range on y axis # |____________________________ range on x axis小孩子千万别在自己家里乱试! _
Tim Perters (他希望这是 Steve Majewski) 建议这个方案: (a and [b] or [c])[0]. 因为 [b] 永远是真值, 于是避开了错误, 然后 [0] 取出想得到的 b, 或是 c. 它看起来挺难看的, 但在某些特殊情况你觉得用 'if' 来写太不方便的话可以考虑用它. 最最最后还有个办法, 就是给 "?:" 操作符定义一个函数:
def q(cond,on_true,on_false):
from inspect import isfunction
if cond:
if not isfunction(on_true): return on_true
else: return apply(on_true)
else:
if not isfunction(on_false): return on_false
else: return apply(on_false)
多数情况下你可直接把 b, c 交给这个函数: q(a,b,c). 如果要避免刚才所说的阱陷,
可以这样调用: q(a, lambda: b, lambda: c).
Paul Boddie 保有一个关于各种架构的综览: http://thor.prohosting.com/~pboddie/Python/web_modules.html
Cameron Laird 的站上则有关于 Python 网站技术的摘要文章: http://starbase.neosoft.com/~claird/comp.lang.python/web_python.html/
甚至有一个用 Python 写的网页浏览器, 叫做 Grail. http://sourceforge.net/project/grail 这个专案已终止了; http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/grail/grail/README 可以看到更多资料.
如果只是做简单的输入分析, 最方便是用 split() 方法把输入字串拆开然后用 int(), long(), float() 得回相对应的数值. (Python 的 int() 是 32-位元的, 而 long() 则支援任意大数.) string.split() 同时接受一个 'seq' 参数, 方便你用空格以外的符号作为分隔符.
要是更复杂些的分析, 可以用正则表达示 (参看 re 模组), 它比 C 的 sscanf() 更强.
有一个模拟 sscanf() 的模组由 Steve Clift 项献出来; 在 ftp 站 http://www.python.org/ftp/python/contrib-09-Dec-1999/Misc/ 的 contrib/Misc/sscanfmodule.c 找到.
虽然有些意想不到, 只要小心思考一下就能明白. 一方面, 在赋值时强制使用 global 宣告可以避免不小心导致的错误. 另一方面, 如果所有的全局变数都一定要用 global 则会太罗嗦, 因为如此一来你就必需使用每个内建函数, 或是便用载入的模组时都要用 global 宣告一次. Python 的做法实为取两者之便.
字典类有个 copy() 的方法可用, 至于序列, 可以用取片断的方法复制: new_lis = old_lis[:]
移除目录用 os.rmdir(); 创立目录用 os.mkdir()
改名有 os.rename().
要截短档案, 用 f = open(filename, "r+") 把档案开成读写模式, 然后用 f.truncate(offset); offset 的预设值就是 当前的位置(即档案末尾). 对于资深的 Unix 用户, 可以用 os.ftruncate(fd, offset) 来截切用 os.open() 打开的档案.
另外, shutil 模组中也有一堆操作档案的函数, 包括 copyfile, copytree, rmtree 等等.
这些函数都只限于十进位数, 因此 int('0144') == 144, 而 int('0x144') 则报错. 在 Python 2.0 中, int() 可以额外加一个基底选项, 象这样: int('0x144', 16) == 324.
用 string 模组中的 atoi(), atol(), atof() 等都可以, 请看函数库参考手册.
不建议用 eval() 方法来做转换. 因为这样做不十分安全.
list() 函数则接收序列引数, 传回相对应的列表. list((1, 2, 3)) 得到 [1, 2, 3] 而 list('abc') 得到 ['a', 'b' 'c']. 如果引数已是列表, 则 list() 会传回一个新建立的列表, 就象用 [:] 那样
def handler(signum, frame): ...
库参考手册中有一个 random 模组, 其中有随机数产生器. 用法异常简单:
import random random.random()传回一个 0 至 1 之间(不包括 1) 的小数 [0,1). 在该模组中还有许多特别订制的函数, 提供方便
randrange(a, b) 从 [a, b) 范围中随机挑选一个整数 uniform(a, b) 在 [a, b) 中随机传回一个小数 normalvariate(mean, sdev) 则随机自一个高斯分布中取样另外还有些函数直接对序列类进行操作:
choice(S) 自序列 S 中随机挑一个数 shuffle(L) 则打散序列, 等于重新排列一个序列 (注意是直接操作 in-place)
DOS 则可试试 Hans Nowak 的 Python-DX, 它支援 RS-232 功能: http://www.cuci.nl/~hnowak/
Unix, 看 Mitch Chapman 在 usenet 上的贴文: http://groups.google.com/groups?selm=34A04430.CF9@ohioee.com
Win32, POSIX(Linux, BSD, *), Jython, 上 Chris 的 http://pyserial.sourceforge.net
以上例程算档案中读取两个 2字元的整数和一个4字元的整数, 用大顺位 big-endian 格式.
import struct
f = open(filename, "rb") # Open in binary mode for portability
s = f.read(8)
x, y, z = struct.unpack(">hhl", s)
其中 '>' 代表一律用大顺位格式来转换数值; 'h' 代表一个 "short integer" (2 字元); 'l' 代表一个 "long integer" (4 字元). 如果要读取的数据十分有规律的话 (比如说是一整串同格式的整数或是浮点数), 你也可以参考 array 模组中关于读取阵列的方法. 同样记载于库参考手册中.
在实际的埸合, 你也许应该这样写:
m = __import__(s) for i in string.split(s, ".")[1:]: m = getattr(m, i)
import termios, fcntl, sys, os
fd = sys.stdin.fileno()
oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
try:
while 1:
try:
c = sys.stdin.read(1)
print "Got character", `c`
except IOError: pass
finally:
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
你要有 termios 及 fcntl 模组才能用到它. 本人只在 Linux 机上测试成功, 但应该别地方也行.
在程式段中, 每次只会读取一个字符. termios.tcsetattr() 把标准输入的 echo 功能关掉同时取消了 canonical 模式. fcntl.fcntl() 用来把标准输入设备的档案记述旗标修改为非等候态 (non-blocking). 另一方面, 读取空的标准输入会引发错误 IOError, 然而在程式段中这个错误指明忽略掉了.
1 try:
2 value = dict[key]
3 except KeyError:
4 dict[key] = getinput(key)
5 value = dict[key]
如果你确信在百分之九十五的情况下 dict[key] 是找得到的, 这个技巧会令程序较快些; 不然的话, 经常处理找不到 key 的异常会影响程序的执行效率. 那时候你应该用下面的写法:
1 if dict.has_key(key):
2 value = dict[key]
3 else:
4 dict[key] = getinput(key)
5 value = dict[key]
6
7 ## In Python 2.0 and higher, of course, you code this as
8 ## value = dict.setdefault(key, getinput(key))
#config.py: pass ------------- #mod.py: import config config.x = 1 ------------- #main.py: import config import mod print config.x注意这也是实现 Singleton design pattern 的基本原则, 道理相似.