今天在啄木鳥社區看到這篇帖子,感覺挺簡潔的,mark一下:
Python 絕對簡明手冊 -- zsp007@gmail.com ::-- ZoomQuiet [2006-09-15 04:35:33]
簡述
1. 閱讀須知
文中使用
>>>
作為會命令行中的輸出信息的前綴
對于不清楚用用途的函數可以在解釋器下面輸入
help(函數名)
來獲取相關信息
另外,自帶的文檔和google也是不可少的
2. 基本語法
2.1. if / elif / else
x=int(raw_input("Please enter an integer:"))#獲取行輸入
if x>0:
print '正數'
elif x==0:
print '零'
else:
print '負數'
此外C語言中類似"xxx?xxx:xxx"在Python中可以這樣寫
>>>number=8
>>>print "good" if 8==number else "bad" #當滿足if條件時返回"good",否則返回"bad"
good
2.2. in
in判斷 一個數 是否在 一個集合(如:元組,列表等) 中
if 'yes' in ('y','ye','yes'):print 'ok'
2.3. for ... in
python中沒有類似C中的for循環,而是使用for...in來對集合中的每一個元素進行操作
a=['cat','door','example']
for x in a:
print x
如果要修改a的內容,請用a的副本循環(否則不安全),如:
a=["cat","zsp007@gmail.com"]
for x in a[:]:
if len(x)>6:a.insert(0,x)
>>>a
['zsp007@gmail.com', 'cat', 'zsp007@gmail.com']
若需要得到循環的次數,參見 函數 range 的用法
2.4. break / continue
這兩個的用法和C中相同
for i in range(10):
if 2==i:continue #結束當前循環,進入下一步循環
if 6==i:break #跳出循環
print i
輸出
0
1
3
4
5
2.5. while / pass
while True:
pass #什么也不做
2.6. is
用來比較兩個變量是否指向同一內存地址(也就是兩個變量是否等價) 而 == 是用來比較兩個變量是否邏輯相等
a=[1,2]
b=[1,2]
>>> a is b
False
>>> a == b
True
2.7. del
用于刪除元素
a=[1,2,3,4,5,6]
del a[0]
a
>>>[2,3,4,5,6]
del a[2:4]
a
>>>[2,3,6]
del a[:]
a
>>>[]
del a
a
#拋出異常
>>>NameError: name 'a' is not defined
2.8. try ... except ... finally / raise
try ... except用于異常處理
try:
x=int(raw_input("請輸入數字:"))
except ValueError: #可以同時捕獲多個異常,寫法如except(RuntimeError,ValueError):
#當輸入非數字時
print"您輸入不是數字"
except: #省略異常名,可以匹配所有異常,慎用
pass
else:#當沒有異常時
print 'result=',result
finally:#和Java中類似。一般用于釋放資源,如文件,網絡連接。
print 'finish'
raise用于拋出異常,可以為自定義的異常類
慣例是以Error結尾的類,同類的異常一般派生自同一個基類(如Exception)
class MyError(Exception):
def __init__(self,value):
self.value=value
def __str__(self):
return reper(self.value)
基類異??梢云ヅ渑缮惍惓?
try:
raise Exception("spam","egg")
except Exception,inst:#inst為該異常類的實例,為可選項
print type(inst) #異常的類型
print inst
3. 內建類型
3.1. None
None 表示該值不存在,比如 沒有定義返回值 的函數就 返回None
3.2. Ture / False
布爾類型,Ture等價于1,False等價于0
3.3. List
>>>test=[1,2,"yes"]
3.3.1. 內建函數
append(x) 追加到鏈尾
extend(L) 追加一個列表,等價于+=
insert(i,x) 在位置i插入x
remove(x) 刪除第一個值為x的元素,如果不存在會拋出異常
reverse() 反轉序列
pop([i]) 返回并刪除位置為i的元素,i默認為最后一個元素(i兩邊的[]表示i為可選的,實際不用輸入)
index(x) 返回第一個值為x的元素,不存在則拋出異常
count(x) 返回x出現的次數
sort() 排序
例子:
>>>test=[1,2,"yes"]
>>>test.append(1) #追加到鏈尾
>>>test
[1, 2, 'yes', 1]
>>>test.extend([ 'no','maybe']) #追加一個列表
>>>test
[1, 2, 'yes', 1, 'no', 'maybe']
>>> test.insert(0,'never') #在位置0插入'never'
>>> test
['never', 1, 2, 'yes', 1, 'no', 'maybe']
>>> test.remove('no') #刪除第一個值為"no"的元素,如果不存在會拋出異常
>>> test
['never', 1, 2, 'yes', 1, 'maybe']
>>> test.reverse() #反轉序列
>>> test
['maybe', 1, 'yes', 2, 1, 'never']
>>> test.pop() #返回并刪除位置為i的元素,i默認為最后一個元素
'never'
>>> test
['maybe', 1, 'yes', 2, 1]
>>> test.index('yes') #返回第一個值為'yes'的元素,不存在則拋出異常
2
>>> test.count(1) #返回1出現的次數
2
>>>test.sort() #排序
>>> test
[1, 1, 2, 'maybe', 'yes']
3.3.2. 切片
從序列中抽取一部分
>>> test=['never', 1, 2, 'yes', 1, 'no', 'maybe']
>>> test[0:3] #包括test[0],不包括test[3]
['never', 1, 2]
>>> test[0:6:2] #包括test[0],不包括test[6],而且步長為2
['never', 2, 1]
>>> test[:-1] #包括開始,不包括最后一個
['never', 1, 2, 'yes', 1, 'no']
>>> test[-3:] #抽取最后3個
[1, 'no', 'maybe']
>>>test[::-1] #倒序排列
['maybe', 'no', 1, 'yes', 2, 1, 'never']
3.3.3. 列表推導式
可以直接通過for循環生成一個list
>>>freshfruit=[' banana ',' loganberry ']
>>>[weapon.strip() for weapon in freshfruit]
['banana', 'loganberry']
說明:strip()是去除字符串兩端多于空格,該句是去除序列中的所有字串兩端多余的空格
>>>vec=[2,4,6]
>>>[3*x for x in vec if x>3]
[12, 18]
>>>[(x,x**2) for x in vec]
#循環變量要是一個sequence,而[x,x**2 for x in vec]是錯誤的
[(2,4),(4,16),(6,36)]
>>>vec2=[4,3,-9]
>>>[x*y for x in vec for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>>>[vec[i]+vec2[i] for i in range(len(vec))]
[6, 7, -3]
>>>[str(round(355/113.0,i)) for i in range(1,6)]
#str()是轉換類型為可以打印的字符
#round(x,n)表示對x保留n位小數(四舍五入)
['3.1', '3.14', '3.142', '3.1416', '3.14159']
3.4. 元組
一旦初始化便不能更改的數據結構,速度比list快
>>>t=1234,5567,'hello' #t=(1234,5567,'hello')的簡寫
>>>x,y,z=t #拆分操作可以應用于所有sequence
>>>x
1234
>>>u=t,(1,2,3)
>>>u
((1234,5567,'hello'),(1,2,3))
>>>empty=() #空元組
>>>singleton='hi', #單個元素的元組,注意逗號
通過元組可以很簡單的進行數據交換. 比如:
a=1
b=2
a,b=b,a
3.5. set
set(集合):無序不重復的元素集
>>>basket = ['apple','orange','apple','pear','apple','banana']
>>>fruit=set(basket)
>>>fruit
set(['orange', 'pear', 'apple', 'banana'])
>>>'orange' in fruit
True
>>>a=set('abracadabew')
>>>a
set(['a', 'c', 'b', 'e', 'd', 'r', 'w'])
>>>b=set('wajgwaoihwb')
>>>b
set(['a', 'b', 'g', 'i', 'h', 'j', 'o', 'w'])
>>>a-b #差
set(['c', 'r', 'e', 'd'])
>>>a|b #并
set(['a', 'c', 'b', 'e', 'd', 'g', 'i', 'h', 'j', 'o', 'r', 'w'])
>>>a&b #交
set(['a', 'b', 'w'])
>>>a^b #(并-交)
set(['c', 'e', 'd', 'g', 'i', 'h', 'j', 'o', 'r'])
3.6. dict
字典:關鍵字為不可變類型,如字符串,整數,只包含不可變對象的元組.
列表等不可以作為關鍵字.
如果列表中存在關鍵字對,可以用dict()直接構造字典.而這樣的列表對通常是由列表推導式生成的.
>>>tel={'jack':4098,'sape':4139}
>>>tel['guido']=4127
>>>tel
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>>tel['jack'] #如果jack不存在,會拋出KeyError
4098
>>>a.get("zsp",5000) #如果"zsp"為tel的鍵則返回其值,否則返回5000
>>>del tel['sape'] #刪除鍵'sape'和其對應的值
>>>tel.keys() #復制一份鍵的副本,同理tel.items()為值的副本
['jack', 'guido']
>>>"jack" in tel #判斷"jack"是否tel的鍵
True
>>>"zsp" not in tel
True
>>>for k,v in tel.iteritems():print k,v #同理tel.iterkeys()為鍵的迭代器,tel.itervalues()為值的迭代器
jack 4098
guido 4127
>>>tel.copy() #復制一份tel
{'jack': 4098, 'guido': 4127}
>>> tel.fromkeys([1,2],0) #從序列生成并返回一個字典,其值為第二個參數(默認為None),不改變當前字典
{1: 0, 2: 0}
>>>tel.popitem() #彈出一項
('jack', 4098)
4. 函數相關
4.1. 函數定義 / 參數默認值
def fib(n=2,a=1):#參數可以有默認值
"""這里給函數寫文檔注釋"""
for i in range(n):
print a
>>>f=fib #可以用一個變量表示函數
>>>f(3)
1
1
1
>>>fib(a=2) #多個可選參數賦值可以直接寫"參數變量名=值"來快速賦值
2
2
4.2. Lambda函數
一種無名函數的速寫法
def make_incrementor(n):
return lambda x: x+n
f=make_incrementor(n)
#f等價于
#def f(x):
# return x+n
4.3. 不定長參數 *para,**para
參數格式為 *para 表示接受一個元組
為 **para 表示接受一個字典
*para要在**para之前
def test(*args,**dic):
for arg in args :
print arg
for k,v in dic.iteritems():
print k ,':',v
>>> test("yes",1,2,me="張沈鵬",where="中國") #"yes",1,2傳遞給元組;me="張沈鵬",where="中國"傳遞給字典
yes
1
2
me : 張沈鵬
where : 中國
4.4. @ 裝飾器
@A def B:pass 等價于 def B:pass B=A(B) 即將函數B作為參數傳給參數A
from time import time
#測試運行時間
def cost_time(func):
def result(*args,**dic):
beign=time()
func(*args,**dic)
print "cost time : ",time()-beign
return result
@cost_time
def show(n):
for x in range(n):print x
>>> show(10)
0
1
2
3
4
5
6
7
8
9
cost time : 0.0469999313354
4.5. 生成器表達式
生成器表達式:類似于沒有中括號的列表推導式,可用在參數中
>>>sum(i*i for i in range(10))
285
>>>unique_words=set(word for line in page for word in line.split())#page為打開的文件
>>>data='golf'
>>>list(data[i] for i in range(len (data)-1,-1,-1))
['f','l','o','g']
4.6. yield
每次調用返回一個值,并記錄當前執行位置所有的變量
def reverse(data):
for index in range(len(data)-1,-1,-1):
yield data[index]
for char in reverse("golf"):
print char,
輸出
f l o g
5. 常用函數
5.1. eval
對字符串參數運算,求值
>>> eval("1 + 2*3") #可以方便的用來做四則運算
7
>>> a=1
>>> eval('a+1') #可以訪問變量
2
5.2. exec
將字符串參數作為python腳本執行
>>> exec('a="Zsp"')
>>> a
'Zsp'
5.3. execfile
和exec類似,不過是用來打開一個文件,并作為python腳本執行
5.4. dir
顯示對象的所有屬性(即可以用"."操作直接訪問)
>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
5.5. help
help(類/函數) 返回相應對象的文檔字符串
>>> help(vars)
Help on built-in function vars in module __builtin__:
vars(...)
vars([object]) -> dictionary
Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
5.6. len
返回序列/字典的長度
>>> len([1,2,3])
3
5.7. print
輸出字符串 用法演示:
print "Today ", #加逗號,輸出后不換行
name="ZSP"
print name,"cost $",10 #輸出多個變量
print "hello,%s!"%name #%s 表示用str轉化為字符串
for x in xrange(1,11):
print '%2d %3d' % (x,x*x) #小數輸出如 %5.3f
對于字典可以用變量名來直接格式化,如:
>>>table={'Sjoerd':4127,'Jack':4098,'Dcab':8637678}
>>>print 'Jack:%(Jack)d; Sjoerd:%(Sjoerd)d; Dcab:%(Dcab)d' %
table
Jack:4098; Sjoerd:4127; Dcab:8637678
同時,函數vars()返回包含所有變量的字典,配合使用,無堅不摧!
5.8. raw_input
x=raw_input("Please enter an sentence:") #將輸入的內容賦值給x
5.9. range
range(10,0,-3)#參數的含義為起點(默認為0),終點(不含終點),步長(默認為1)
>>>[10,7,4,1]
和for...in配合使用
a=['cat','door','example']
for i in range(len(a)):#len()函數為求序列的長度
print i,a[i]
5.10. filter
filter(function , sequence) 返回序列,為原序列中能使function返回true的值
>>>a=[1,2,3,4]
>>>filter(lambda x:x%2,a)
[1, 3]
5.11. map
map(function,sequence,[sequence...])
返回序列,為對原序列每個元素分別調用function獲得的值.
可以傳入多個序列,但function也要有相應多的參數,如
map(lambda x,y,z:x+y+z,range(1,3),range(3,5),range(5,7))
計算過程為
1+3+5=9
2+4+6=12
返回[9,12]
5.12. reduce
reduce(function,sequence,[init])
返回一個單值為,計算步驟為 :
如 reduce(lambda x,y:x+y,range(3),99) 的計算為
99+0=99 => 99+1=100 => 100+2=102
返回102
注:實際使用中用內建函數sum來完成這個累加更合適,如這里等價sum(range(3),99)
5.13. zip
zip用于多個sequence的循環
questions=['name','quest','favorite color']
answers=['lancelot','the holy grail','blue']
for q,a in zip(questions,answers):
print 'What is your %s ? It is %s.'%(q,a)
輸出:
What is your name ? It is lancelot.
What is your quest ? It is the holy grail.
What is your favorite color ? It is blue.
5.14. reversed反向循環
for i in reversed(range(1,4)):
print i
輸出:
3
2
1
5.15. sorted排序
返回一個有序的新序列
>>>sorted([2,5,1,4])
[1, 2, 4, 5]
5.16. enumerate 返回索引位置和對應的值
for i,v in enumerate(['tic','tac','toe'])
print i,v
輸出:
0 tic
1 tac
2 toe
5.17. open/文件操作
f=open('/tmp/hello','w')
#open(路徑+文件名,讀寫模式)
#讀寫模式:r只讀,r+讀寫,w新建(會覆蓋原有文件),a追加,b二進制文件.常用模式
如:'rb','wb','r+b'等等
f.read([size]) size未指定則返回整個文件,如果文件大小>2倍內存則有問題.f.read()讀到文件尾時返回""(空字串)
file.readline() 返回一行
file.readline([size]) 返回包含size行的列表,size 未指定則返回全部行
for line in f: print line #通過迭代器訪問
f.write("hello"n") #如果要寫入字符串以外的數據,先將他轉換為字符串.
f.tell() 返回一個整數,表示當前文件指針的位置(就是到文件頭的比特數).
f.seek(偏移量,[起始位置])
用來移動文件指針
偏移量:單位:比特,可正可負
起始位置:0-文件頭,默認值;1-當前位置;2-文件尾
f.close() 關閉文件
6. 模塊化
6.1. 導入模塊
模塊的查找路徑
1.當前的目錄
2.環境變量PYTHONPATH所指的目錄列表
3.python解釋器的安裝目錄
如將代碼保存上述的一個目錄中的的fibo.py文件中,便可以
import fibo
fibo.function()
如果想直接使用fibo.function可以重命名這個函數,如
f=fibo.function
f()
也可以
form fibo import function
function()
甚至可以form fibo import *
可以 form 包.子包.模塊 imort 函數
然后就直接使用該函數,不需要加前綴
6.2. 包
引用推薦寫法為
form 包 import 模塊
幾個功能類似的模塊可以組合成一個包,
比如一個可以處理.wav,.mp3,.wma等音頻文件的有類似如下結構:
Sound/
__init__.py
Formats/
__init__.py
wavread.py
wavwrite.py
mp3read.py
mp3write.py
wmaread.py
wmawrite.py
Effects/
__init__.py
echo.py
surround.py
reverse.py
只有當init.py存在時python才將該文件夾視為一個包.
該文件可以為空文件 一般在init.py文件中定義一個all列表,包含要import *時要導入的模塊. 如Sound/Effects/init.py可以有如下內容
__all__=["echo","surround","reverse"]
包的作者在發布包時可以更新這個列表,也可以根據需要讓某個模塊不支持import *
對于包中同一個文件夾下的模塊可以把
form 包.子包 imort 模塊
簡寫為 imort 模塊
6.3. 面向對象
6.3.1. 概要
class ClassName:
"類文檔,可以通過類名.__doc__訪問"
def f(self):#self為每個類函數的必要的一個參數,可以通過它來訪問當前實例
return self.content
def __init__(self,word=''):#構造函數
#構造函數,可以初始化變量,可以有參數"
self.content=word
self.__name=word #私有變量,以"__"開頭,不以"__"結尾的變量
創建類實例 x=ClassName("good")
6.3.2. 類繼承
class DerivedClassName(BassClassName):
如果基類定義在另一個模塊中, 要寫成
modname.BaseClassName
派生類的函數會覆蓋基類的同名函數
如果想擴充而不是改寫基類的函數,可以這樣調用基類函數
BaseClassName.methodname(self,arguments)
注意:該基類要在當前全局域或被導入
class A:
def hi(self):
print "A"
class B:
def hi(self):
A.hi(self)
super(B).hi() #通過super關鍵字可以獲得當前類的基類
print "B"
B().hi()
輸出
A
B
6.3.3. 多重繼承
類多繼承
class DerivedClassName(Base1,Base2,Base3):
pass
對于該類函數的解析規則是深度優先,先是Base1,然后是Base1的基類,諸如此類.
class A:
def hi(self):
print "A"
class B:
def hi(self):
print "B"
class C(A,B):
pass
C().hi()
輸出:
A
6.4. 操作符重載
通過定義類的一些約定的以"
"開頭并結尾的函數,可以到達重載一些特定操作的目的,下面是是一些常用的重載
6.4.1. __str__ / __unicode__
當print一個對象實例時,實際是print該實例
str()函數的返回值.
class A:
def __str__(self):
return "A"
def __unicode__(self):
return "uA"
print A()
print unicode(A())
輸出
A
uA
unicode和str
類似,不過返回Unicode字符串.
6.4.2. 比較操作
x<y x.
lt(y)
x<=y x.
le(y)
x==y x.
eq(y)
x!=y 或 x<>y x.
ne(y)
x>y x.
gt(y)
x>=y x.
ge(y) cmp
( self, other) 用來簡化比較函數的定義 self < other返回負數,相等時返回0,self>other時返回正數
class A:
def __init__(self,i):
self.i=i
def __cmp__(self,other):
return self.i-other.i
print A(1)>A(2)
輸出
False
6.4.3. __iter__
for ... in 循環即就是通過這個函數遍歷當前容器的對象實例 可配合yield方便的編寫這個函數(參見基本語法yield)
class A:
def __init__(self,n):
self.n=n
def __iter__(self):
n=self.n
while n:
m=n%2
n/=2
yield m
for i in A(5):
print i,
輸出
1 0 1
另有一種繁瑣的實現: 返回一個可以通過next()函數遍歷的對象,當結束時拋出StopIteration異常
6.5. 類相關函數
6.5.1. type
返回對象的類型
>>> type("")
<type 'str'>
>>> type("")==str
True
>>> type([])
<type 'list'>
>>> type([])==list
True
>>> type({})
<type 'dict'>
>>> type(())
<type 'tuple'>
>>> class A:pass
>>> type(A)
<type 'classobj'>
>>> type(A())
<type 'instance'>
>>> import types #在types模塊中有許多類型的定義
>>> type(A)==types.ClassType
True
6.5.2. getattr / hasattr /delattr
getattr:通過類實例和一個字符串動態的調用類函數/屬性
class A:
def name(self):
return "ZSP"
def hello(self):
return "nice to meet me ."
def say(obj,attr):
print getattr(obj,attr)()
a=A()
say(a,"name")
say(a,"hello")
輸出
ZSP
nice to meet me .
hasattr 用來判斷實例有無該函數/屬性
delattr 用來刪除實例的函數/屬性
6.5.3. property
通過值的方式調用實例無參函數
class A(object):
def __init__(self): self._x = None
def getx(self): return self._x
def setx(self, value): self._x = value
def delx(self): self._x=None
x = property(getx, setx, delx, "I'm the 'x' property.")
a=A()
print a.x
a.x="ZSP"
print a.x
del a.x
print a.x
輸出
None
ZSP
None
可以方便的定義一個只讀屬性
class A(object):
@property
def x(self): return "Property"
調用
>>>a=A()
>>>print a.x
Property
>>>a.x="ZSP" #只讀屬性,不能更改
Traceback (most recent call last):
File "D:"Profile"Untitled 2.py", line 9, in <module>
a.x="ZSP"
AttributeError: can't set attribute
6.5.4. isinstance( object, classinfo)
判斷一個對象是否是一個類的實例
>>>class A:pass
>>>class B:pass
>>>a=A()
>>>isinstance(a,A)
True
>>>isinstance(a,B)
False
Python 常用模塊體驗 ::-- ZoomQuiet [2007-11-10 06:37:48]
7. Py常用模塊匯編
'Python 標準庫2.0 整理者
Python 江湖 QQ 群: 43680167
Feather (校對) gt: andelf@gmail.com
::-- ZoomQuiet [2007-11-10 07:39:01]
7.1. zshelve 對象持久模塊
Jiahua Huang <jhuangjiahua@gmail.com>
reply-to python-cn@googlegroups.com,
to "python. cn" <python-cn@googlegroups.com>,
date Nov 8, 2007 5:41 PM
subject [CPyUG:34726] 貼個 zlib 壓縮的 zshelve 對象持久模塊
這個給 Python 標準庫的 shelve.py 添加了 zlib 壓縮, 減小數據庫文件體積,以改善磁盤 io 性能
7.1.1. 發布
http://zshelve.googlecode.com/svn/trunk/
加了個命令行工具:
huahua@huahua:tmp$ zshelve
commandline tool for zshelve databases
Usage: zshelve FILE dump Dump the data tree
zshelve FILE keys List of keys
zshelve FILE get KEY Dump value for key
zshelve FILE set KEY VALUE Set db[key] = value
zshelve FILE has_key KEY True if database has the key
zshelve FILE search_key KEY Search key
zshelve FILE search_value VALUE Search value
huahua@huahua:tmp$ zshelve set tes.db a 1
huahua@huahua:tmp$ zshelve dump tes.db
|- a
| | - 1
huahua@huahua:tmp$ zshelve set tes.db b "dict(a=1,b=2,c=3,d={'s':'4'})"
huahua@huahua:tmp$ zshelve dump tes.db
|- a
| |- 1
|- b
| |- a
| | |- 1
| |- c
| | |- 3
| |- b
| | |- 2
| |- d
| | |- s
| | | |- 4
對比::
>>> import zshelve
>>> import shelve
>>> zdb = zshelve.open('/tmp/zshelve.db')
>>> db = shelve.open('/tmp/shelve.db')
>>> zdb['1'] = dict(a='0123456789'*10000000)
>>> db['1'] = dict(a='0123456789'*10000000)
>>> zdb.sync()
>>> db.sync()
看看文件大小差異::
huahua@huahua:zshelve$ ll /tmp/*shelve.db
-rw-r--r-- 1 huahua huahua 96M 2007-11-08 17:36 /tmp/shelve.db
-rw-r--r-- 1 huahua huahua 204K 2007-11-08 17:36 /tmp/zshelve.db
7.1.2. 補丁::
--- shelve.py 2007-05-03 00:56:36.000000000 +0800
+++ zshelve.py 2007-11-08 17:25:59.000000000 +0800
@@ -70,6 +70,7 @@ except ImportError:
import UserDict
import warnings
+import zlib ## use zlib to compress dbfile
__all__ = ["Shelf","BsdDbShelf","DbfilenameShelf","open"]
@@ -80,13 +81,14 @@ class Shelf(UserDict.DictMixin):
See the module's __doc__ string for an overview of the interface.
"""
- def __init__(self, dict, protocol=None, writeback=False):
+ def __init__(self, dict, protocol=None, writeback=False, compresslevel=2):
self.dict = dict
if protocol is None:
protocol = 0
self._protocol = protocol
self.writeback = writeback
self.cache = {}
+ self.compresslevel = compresslevel
def keys(self):
return self.dict.keys()
@@ -109,7 +111,7 @@ class Shelf(UserDict.DictMixin):
try:
value = self.cache[key]
except KeyError:
- f = StringIO(self.dict[key])
+ f = StringIO(zlib.decompress(self.dict[key]))
value = Unpickler(f).load()
if self.writeback:
self.cache[key] = value
@@ -121,7 +123,7 @@ class Shelf(UserDict.DictMixin):
f = StringIO()
p = Pickler(f, self._protocol)
p.dump(value)
- self.dict[key] = f.getvalue()
+ self.dict[key] = zlib.compress(f.getvalue(), self.compresslevel)
def __delitem__(self, key):
del self.dict[key]
@@ -168,32 +170,32 @@ class BsdDbShelf(Shelf):
See the module's __doc__ string for an overview of the interface.
"""
- def __init__(self, dict, protocol=None, writeback=False):
- Shelf.__init__(self, dict, protocol, writeback)
+ def __init__(self, dict, protocol=None, writeback=False, compresslevel=2):
+ Shelf.__init__(self, dict, protocol, writeback, compresslevel)
def set_location(self, key):
(key, value) = self.dict.set_location(key)
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())
def next(self):
(key, value) = self.dict.next()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())
def previous(self):
(key, value) = self.dict.previous()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())
def first(self):
(key, value) = self.dict.first()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())
def last(self):
(key, value) = self.dict.last()
- f = StringIO(value)
+ f = StringIO(zlib.decompress(value))
return (key, Unpickler(f).load())
@@ -204,12 +206,12 @@ class DbfilenameShelf(Shelf):
See the module's __doc__ string for an overview of the interface.
"""
- def __init__(self, filename, flag='c', protocol=None, writeback=False):
+ def __init__(self, filename, flag='c', protocol=None,
writeback=False, compresslevel=2):
import anydbm
- Shelf.__init__(self, anydbm.open(filename, flag), protocol, writeback)
+ Shelf.__init__(self, anydbm.open(filename, flag), protocol,
writeback, compresslevel)
-def open(filename, flag='c', protocol=None, writeback=False):
+def open(filename, flag='c', protocol=None, writeback=False, compresslevel=2):
"""Open a persistent dictionary for reading and writing.
The filename parameter is the base filename for the underlying
@@ -222,4 +224,4 @@ def open(filename, flag='c', protocol=No
See the module's __doc__ string for an overview of the interface.
"""
- return DbfilenameShelf(filename, flag, protocol, writeback)
+ return DbfilenameShelf(filename, flag, protocol, writeback, compresslevel)
::-- ZoomQuiet [2007-11-10 07:34:49]
7.2. fast UserDict
Jiahua Huang <jhuangjiahua@gmail.com>
reply-to python-cn@googlegroups.com,
to "python. cn" <python-cn@googlegroups.com>,
date Nov 10, 2007 3:28 PM
subject [CPyUG:34791] 一行代碼讓 UserDict.UserDict 的類加速 4 倍
發現 Python 標準庫里好些字典類從 UserDict.UserDict 派生, 而不是從 dict 派生, 是因為 舊版 python 內建類型不能派生子類,
那么這會不會影響速度呢,
先給兩個分別繼承 UserDict.UserDict 和 dict 的類 URdict, Rdict
>>> import UserDict
>>> class URdict(UserDict.UserDict):
... '''dict can search key by value
... '''
... def indexkey4value(self, value):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.indexkey4value('Other')
... 'b'
... '''
... try:
... ind = self.values().index(value)
... return self.keys()[ind]
... except:
... return None
... def key4value(self, svalue):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.key4value('Other')
... 'b'
... '''
... for key, value in self.iteritems():
... if value == svalue:
... return key
... def keys4value(self, svalue):
... '''search keys by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.keys4value('Other')
... ['b', 'e']
... '''
... keys=[]
... for key, value in self.iteritems():
... if value == svalue:
... keys.append(key)
... return keys
...
>>>
>>> class Rdict(dict):
... '''dict can search key by value
... '''
... def indexkey4value(self, value):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.indexkey4value('Other')
... 'b'
... '''
... try:
... ind = self.values().index(value)
... return self.keys()[ind]
... except:
... return None
... def key4value(self, svalue):
... '''search key by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.key4value('Other')
... 'b'
... '''
... for key, value in self.iteritems():
... if value == svalue:
... return key
... def keys4value(self, svalue):
... '''search keys by value
... >>> rd = Rdict(a='One', b='Other', c='What', d='Why', e='Other')
... >>> rd.keys4value('Other')
... ['b', 'e']
... '''
... keys=[]
... for key, value in self.iteritems():
... if value == svalue:
... keys.append(key)
... return keys
...
>>>
>>> import time
>>> def _timeit(_src):
... exec('''
... _t0 = time.time()
... %s
... _t1 = time.time()
... _t3 = _t1 - _t0
... '''%_src)
... return _t3
...
>>> ran = range(100000)
再弄倆實例
>>> u = URdict()
>>> r = Rdict()
看看插入速度
>>> _timeit("for i in ran: u[i]=i")
0.1777961254119873
>>> _timeit("for i in ran: r[i]=i")
0.048948049545288086
看看原始 dict 的速度
>>> _timeit("for i in ran: d[i]=i")
0.041368961334228516
可以看到, UserDict.UserDict 確實嚴重影響速度,
python 標準庫里邊好多 UserDict 的都應該換成 dict , 以提高性能
不過,一個個修改 Python 標準庫似乎又不合適,
再次使用一招鮮,直接干掉 UserDict
在使用/導入那些模塊前先來一行
>>> import UserDict; UserDict.UserDict = dict
完了再導入模塊來試試
>>> u = URdict()
>>> _timeit("for i in ran: u[i]=i")
0.042366981506347656
一行代碼讓速度提高 4 倍