天天看点

python-cookbook学习笔记一

python-cookbook这边书里面有很多实用的python模块介绍,这里将我的学习笔记共享下。我用的是python-cookbook第三版,python-cookbook第三版是针对python3.3的,我采用的还是2.7.6. 但多数模块都能兼容

假设有M个元素的列表,需要从中分解出N个对象,N<M,这会导致分解的值过多的异常。如下:

record=['zhf','[email protected]','775-555-1212','847-555-1212']
name,email,=record      

E:\python2.7.11\python.exeE:/py_prj/python_cookbook.py

Traceback (most recent call last):

 File "E:/py_prj/python_cookbook.py", line 9, in <module>

   name,email,=record

ValueError: too many values to unpack

提示too manyvalues to unpack

在python3中可以用*表达式来解决

record=['zhf','[email protected]','775-555-1212','847-555-1212']
name,email,*phone_number=record      
此时name=’zhf’,email=’[email protected]’      
Phone_number=['775-555-1212','847-555-1212']      
但是此类用法仅限于3.0. 2.7.6版本会报错      
(二)      
保存最后N个元素:      
有的时候我们希望保存查找到元素的最后前5个元素,比如文件有如下内容:      
This is a c test      
This is a java test      
This is a go test      
This is a c++ test      
This is a mysql test      
This is a javascript test      
This is a perl test      
This is a ruby test      
This is a python test      
This is a essamble test      
This is a linux test      
我们想找到This is a python test的前5个记录。我们可以用collections.deque来实现。 Deque(maxlen=N)创建了一个固定长度的队列,当有新记录加入队列而队列已满时会自动移除最老的记录。实现FIFO的功能。实现代码如下:      
def search(lines,pattern,history=5):      
#创建一个长度为5的队列
    previous_line=deque(maxlen=history)
    for line in lines:
        if pattern in line:
            yield line,previous_line      
#将查找到pattern之前的信息插入队列
        previous_line.append(line)

if __name__=='__main__':
    f=open(r'E:\py_prj\test.txt')
    for line,previous in search(f,'python',5):
        for plines in previous:      
#打印出最后5条信息
            print plines      
#打印出查找到的pattern
        print line      
结果如下:previous保存了This is a python test的前5条信息      
E:\python2.7.11\python.exe E:/py_prj/python_cookbook.py      
This is a c++ test      
This is a mysql test      
This is a javascript test      
This is a perl test      
This is a ruby test      
This is a python test      

下面的例子更直观的表现了deque的功能,当达到最大数量的时候,删除最早的元素,然后在末端插入新的元素

>>> from collections import deque

>>> q=deque(maxlen=3)

>>> q.append(1)

>>> q.append(2)

>>> q.append(3)

>>> q

deque([1, 2, 3], maxlen=3)

>>> q.append(4)

>>> q

deque([2, 3, 4], maxlen=3)

>>> q.append(5)

>>> q

deque([3, 4, 5], maxlen=3)

如果不指定大小,那么则是无限大的队列,可以appendleft在左端插入元素,也可以用popleft来将最左边的出队列

>>> q=deque()

>>> q.append(1)

>>> q.append(2)

>>> q.append(3)

>>> q.appendleft(4)

>>> q

deque([4, 1, 2, 3])

>>> q.popleft()

4

三 找到最大的N个元素:

Heapq模块有2个函数,nlargest()和nsmallest()可以解决这个问题

import heapq      
nums=[1,8,2,10,4,5,6,19,20]
largest=heapq.nlargest(3,nums)
print largest      

得到结果:

[20, 19, 10]

[1, 2, 4]

我们还可以导入更复杂的数据结构进行比较:如下面的结构。里面包含了6个元素,都是字典类型的。如何根据price对他们进行排序呢

portfolio = [
{'name': 'IBM', 'shares': 100, 'price': 91.1},
{'name': 'AAPL', 'shares': 50, 'price': 543.22},
{'name': 'FB', 'shares': 200, 'price': 21.09},
{'name': 'HPQ', 'shares': 35, 'price': 31.75},
{'name': 'YHOO', 'shares': 45, 'price': 16.35},
{'name': 'ACME', 'shares': 75, 'price': 115.65}
]      

我们来看下heapq.nlargest的帮助手册。原型函数中第一个参数是返回的数目,第二个参数表明是可迭代对象。第三个参数key值默认为None

Help on function nlargest in module heapq:

nlargest(n, iterable, key=None)

   Find the n largest elements in a dataset.

   Equivalent to:  sorted(iterable,key=key, reverse=True)[:n]

这个key值和sorted的key值是一个作用,这个key值指定可迭代对象中的一个元素来进行排序。也就是从第二个参数中接受一个参数进行处理,最后得到一个元素。函数会根据这个元素来进行排序。那么前面的例子中,每个迭代对象返回一个字典。那么key值的作用就是从这个字典中取出一个关键参数作为排序的参考。

代码改造如下:使用lambda来实现这个函数功能。这个s值就是portfolio中返回的每个字典值。取出其中price字段进行排序

largest=heapq.nlargest(3,portfolio,key=lambda s:s['price'])
samllest=heapq.nsmallest(3,portfolio,key=lambda s:s['price'])      

结果如下:

[{'price': 543.22, 'name': 'AAPL', 'shares':50}, {'price': 115.65, 'name': 'ACME', 'shares': 75}, {'price': 91.1, 'name':'IBM', 'shares': 100}]

[{'price': 16.35, 'name': 'YHOO', 'shares':45}, {'price': 21.09, 'name': 'FB', 'shares': 200}, {'price': 31.75, 'name':'HPQ', 'shares': 35}]

通过heapq的名字可以看出,这是将一个数据对象用堆排序并取得最大最小的值。具体是如何来实现的呢。我们首先来看下heapq.heapify这个函数

nums=[1,8,2,10,4,5,6,19,20]      
heapq.heapify(nums)      
print nums      

结果如下:

[1, 4, 2, 10, 8, 5, 6, 19, 20]

其实heapfify就是生成一个最小堆的树型结构。具体最小堆的定义可以参考数据结构。最小堆就是子节点大于父节点。结构如下所示:

1,8,2,10,4,5,6,19,20的树形结构如下      
python-cookbook学习笔记一
因此根据这个结构我们就可以用heapq.heappop(nums)得到最小的元素。其实每次heappop执行的过程都是一次堆重新排序的过程,自动将最小的元素排在父节点。整个执行过程如下:      
>>> nums=[1,8,2,10,4,5,6,19,20]      
#首先必须要用heapify将数据转换成堆的形式      
>>> heapq.heapify(nums)      
>>> nums      
[1, 4, 2, 10, 8, 5, 6, 19, 20]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
1      
>>> nums      
[2, 4, 5, 10, 8, 20, 6, 19]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
2      
>>> nums      
[4, 8, 5, 10, 19, 20, 6]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
4      
>>> nums      
[5, 8, 6, 10, 19, 20]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
5      
>>> nums      
[6, 8, 20, 10, 19]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
6      
>>> nums      
[8, 10, 20, 19]
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
8      
>>> nums      
[10, 19, 20]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
10      
>>> nums      
[19, 20]      
python-cookbook学习笔记一
>>> heapq.heappop(nums)      
19      
>>> nums      
[20]      
从上面的过程可以看到,其实每次heappop都是一次树型结构的调整,自动会将最小的元素上浮到父节点,      
python中上浮和下沉的具体实现函数如下,有兴趣的可以研究下。      
def _siftup(heap, pos):

    endpos = len(heap)

    startpos = pos

    newitem = heap[pos]

    # Bubble up the smaller child until hitting a leaf.

    childpos = 2*pos + <span  style="" color:"="">1    # leftmost child position

    while childpos < endpos:

        # Set childpos to index of smaller child.

        rightpos = childpos + 1

        if rightpos < endpos and not cmp_lt(heap[childpos], heap[rightpos]):

            childpos = rightpos

        # Move the smaller child up.

        heap[pos] = heap[childpos]

        pos = childpos

        childpos = 2*pos + 1

    # The leaf at pos is empty now.  Put newitem there, and bubble it up

    # to its final resting place (by sifting its parents down).

    heap[pos] = newitem

    _siftdown(heap, startpos, pos)