《Python高级编程技巧》学习笔记
2-1列表、字典、集合筛选数据
- filter
from random import randint
data = [randint(-10,10) for _ in xrange(10)]
filter(lambda x : x>=0,data)
- 推导式
在 Ipython 中使用 timeit
可以进行计时
timeit filter(lambda x : x =='a',data)
2-2命名元祖
from collections import namedtuple
p = namedtuple('Point',['x','y'])
p.x,p.y=1,2
print p.x+p.y
2-3 统计元素出现频率
from collections import Counter
from random import randint
data = [randint(0,20) for _ in xrange(20)]
c = Counter(data)
print c.most_common(1)
2-4根据字典的值排序
- 使用 zip
- 使用 sort
from random import randint
d = {x:randint(0,100) for x in 'xyzabc'}
print sorted(zip(d.values(),d.keys()))
print sorted(d.items(),key=lambda x:x[1])
2-5获取字典公共键
1.使用 viewkeys
方法获得集合再取交集
2.使用 map
函数获取所有字典的 key 的集合
3.使用 reduce
函数依次取交集
from random import randint,sample
s1={x:randint(1,4) for x in sample('abcdefg',randint(3,6))}
s2={x:randint(1,4) for x in sample('abcdefg',randint(3,6))}
s3={x:randint(1,4) for x in sample('abcdefg',randint(3,6))}
reduce(lambda a,b:a&b,map(dict.viewkeys,[s1,s2,s3]))
2-6有序字典
from time import time
from random import randint
from collections import OrderedDict
d = OrderedDict()
players = list('ABCDEFGH')
start = time()
for i in xrange(8):
raw_input()
p = players.pop(randint(0,7-i))
end = time()
print i+1,p,end -start,
d[p]=(i+1,end-start)
print
for k in d:
print k,d[k]
2-7利用队列实现历史记录
from collections import deque
q = deque([],5)
3-1可迭代对象和迭代器对象
- 可迭代对象能够通过
iter()
函数得到一个迭代器对象 - 实现了
__iter__
和__getitem__
方法的对象是可迭代对象
3-2实现可迭代对象和迭代器
- 可迭代对象,要实现
__iter__
方法,该方法要返回一个迭代器。 - 迭代器要实现一个
next()
函数,该函数返回一个结果,同时需要在结束时抛出StopIteraion
异常 - 可以直接把
__iter__
实现为一个生成器
3-4实现反向迭代
- 实现
__reversed__
函数
class FloatRange:
def __init__(self, start, end, step=0.1):
self.start = start
self.end = end
self.step = step
def __iter__(self):
t = self.start
while t <= self.end:
yield t
t += self.step
def __reversed__(self):
t = self.end
while t >= self.start:
yield t
t -= self.step
for x in reversed(FloatRange(1.0, 4.0, 0.5)):
print x
3-5对可迭代对象使用切片
from itertools import islice
Docstring:
islice(iterable, [start,] stop [, step]) --> islice object
Return an iterator whose next() method returns selected values from an
iterable. If start is specified, will skip all preceding elements;
otherwise, start defaults to zero. Step defaults to one. If
specified as another value, step determines how many values are
skipped between successive calls. Works like a slice() on a list
but returns an iterator.
Type: type
这个函数使用后,会消耗掉已经生成的元素
3-6同时迭代多个可迭代对象
- 并行:
zip()
- 串行:
from itertools import chain
4-1拆分多种分隔符的字符串
- 反复使用
split
函数
def mysplit(s,ds):
res = [s]
for d in ds:
t = []
map(lambda x : t.extend(x.split(d)),res)
res = t
return res
- 使用
re.split()
函数
4-3 如何调整字符串中文本的格式
re.sub('(\d{4})-(\d{2})-(\d{2})',r'\2/\3/\1',log)
4-4拼接多个短字符串
- 累加
-
join()函数
,接受一个可迭代的字符串对象
4-5 如何对字符串进行左, 右, 居中对齐
-
str.ljust()
,str.rjust()
,str.center()
s.ljust(20,'*')
Out[13]: 'abc*****************'
-
format()
配置参数>20 <20 ^20
format(s,'<20')
Out[19]: 'abc '
4-6 如何去掉字符串中不需要的字符
-
strip(),lstrip(),rstrip()
去除两端字符 -
re.sub
或者replace
translate
S.translate(table [,deletechars]) -> string
Return a copy of the string S, where all characters occurring
in the optional argument deletechars are removed, and the
remaining characters have been mapped through the given
translation table, which must be a string of length 256 or None.
If the table argument is None, no translation is applied and
the operation simply removes the characters in deletechars.
Type: builtin_function_or_method
5 文件操作
6 解析 cvs,xml,excel,json
6.1解析 cvs
import cvs
rf = open('file.cvs','rb')
reader = cvs.reader(rf)#生成器
reader.next()
wf = open('file.cvs','r')
writer = cvs.writer(wf)#生成器
writer.next()
6.2解析 xml
7 类与对象
7-1 如何派生内置不可变类型并修改实例化行为
派生一个元组类型,只保留整型
class IntTuple(tuple):
def __new__(cls,iterable):
g = (x for x in iterable if isinstance(x,int))
return super(IntTuple,cls).__new__(cls,g)
def __init__(self,iterable):
super(IntTuple,self).__init__(iterable)
t = IntTuple([1,-1,'abc',['x','y'],3])
print t
7-2 利用__slot__
来节省对象的内存开销
当我们不使用__slot__
时,类对象使用一个 dict 来对对象的属性进行动态绑定。对象的属性就是该字典中的一个元素,可以动态添加或解除。
p = Player()
p.__dict__['x']=1
>> p.x = 1
该机制需要维护一个字典,占据大量空间。
使用预定义的 __slot__ = ['x','y']
,可以预定义对象的属性,不允许动态添加。
7-3 如何让对象支持上下文管理
让对象支持 with 语句,需要定义 __enter__
和__exit__
函数
def __enter__(self):
self.tn = Telnet()
return self
def __exit__(self):
self.tn.close()
当发生异常时,能正确调用__exit__
,如果该函数返回一个 True,则可以压制 with 语句中的异常。
7-4 如何创建可管理的对象属性
利用 getter 和 setter 来管理对象属性,但是这样做调用起来比较麻烦。可以使用@property
装饰器来简化
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
当然也可以利用property()
函数
R = property(getter,setter)
C.R = 1 #调用 getter
print C.R #调用 setter
7-5 如何让类支持比较操作
- 实现
__lt__
,__ie__
,__gt__
,__ge__
,__eq__
,__ne__
- 装饰器
@total_ordering
可以通过逻辑运算自动进行推测,我们可以只定义小于和等于两种比较运算符 - 对于两个不同的类的对象,如果其中一个类实现了比较,那么当这个类作为比较运算符的左值时才可以正确执行,否则不等式两边的类都要实现全部相关比较操作符
- 为了应对上述问题,我们可以定义一个抽象的公共基类
from abc import abstractmethod
class shape(object):
@abstractmethod
def area(self):
pass
def __lt__(self,obj):
return self.area()<obj.area()
class rect(shape):
def area(self):
return self.x * self.y
class tri(shape):
def area(self):
return 0.5*self.x * self.h
7-6 如何使用描述符对实例属性做类型检查
8 多线程
8-1 如何使用多线程
from threading import Thread
class myThread(Thread):
def __init__(self,sid):
Thread.__init__(self)
self.sid = sid
def run(self):
handle(self.sid)
threads = []
for i in range(1,11):
t = myThread(i)
threads.append(t)
t.start()
for t in threads:
t.join() #必须在不同的循环中调用 join 否则会依次阻塞变成线性执行
python 中的线程只适合处理 IO 密集型操作而不是 CPU 密集型操作
8-2 如何线程间通信
定义两个线程,Downloader
和 Coverter
前者是生产者,后者是消费者
可以通过一个全局变量来进行数据通信,但是再操作数据前要调用 lock 函数加锁。或者可以使用线程安全的数据结构,例如from Queue import Queue
。
通常情况下,使用全局变量是不优雅的,可以通过构造器将队列传入,并使用 self.queue来维护。
8-3 如何在线程间进行事件通知
每下载100个 xml 文件,通知压缩线程来压缩,压缩线程执行完毕后,再通知下载函数继续下载
ipython 中输入!开头的命令,可以执行 shell 命令
from threading import Event,Thread
class CovertThread(Thread):
def __init__(self,cEvent,tEvent):
Thread.__init__(self)
self.cEvent = cEvent
self.tEvent = cEvent
self.count = 0
def csv2xml(self,data,wf):
pass
def run():
count = 1
while True:
self.csv2xml(data,wf):
count +=1
id count == 100:
self.cEvent.set()
self.tEvent.wait()
self.cEvent.clear()
count = 0
class TarThread(Thread):
def __init__(self,cEvent,tEvent):
Thread.__init__(self)
self.cEvent = cEvent
self.tEvent = cEvent
self.count = 0
self.setDaemon(True) #设置为守护进程
def tarXml(self):
self.count += 1
tfname = '%d.tar'%self.count
tf = tarfile.open(tfname,'w:gz')
for fname in os.listdir('.'):
if fname.endwith('xml'):
tf.add(frame)
os,remove(fname)
tf.close()
if not tf.members:
os.remove(tfname)
def run(self):
while True:
self.cEvent.wait() #等待事件
self.tarXml() #打包
self.cEvent.clear() #清空当前状态
self.tEvent.set() #发送消息
共同维护两个 Event,并通过 set 和 wait 来发送消息,通过clear 清除当前状态。