1.1 将序列分解为单独变量
问题:有一个包含N个元素的元组或序列,将其分解成N个单独的变量。
解决方案:任何序列,或可迭代的对象都可以通过一个简单的复制操作来分解为单独变量。唯一的要求是变量的总数和结构要与序列相吻合,否则报错。例如:
>>> a=[1,2,3,'ab',('c','d')]
>>> x,y,z,b,c=a
>>> x
1
>>> y
2
>>> z
3
>>> b
'ab'
>>> c
('c', 'd')
1.2 从任意长度的可迭代对象中分解元素
问题:需要从某个可迭代对象中分解出N个元素,但是这个可迭代对象的长度可能超过N,这会导致出现“分解的值过多”的异常。
解决方案:Python的*表达式可用于解决此问题。例如:假设开了一门课程,决定统计成绩时去掉第一个和最后一个,仅对中间的成绩进行统计。则下列函数可实现此功能:
def drop(grades):
first,*middle,last=grades
return avg(middle)
由*修饰的变量也可以放在开头。
**讨论:**当和某些特定的字符串处理操作相结合,比如做拆分(splitting)操作时,这种*式的语法所支持的分解操作也非常有用。例如:
>>> line='Jack:18:1200210:Class 2,Grade 3:No.1 Senior High'
>>> name,age,*ID,school=line.split(':')
>>> name
'Jack'
>>> age
'18'
>>> ID
['1200210', 'Class 2,Grade 3']
>>> school
'No.1 Senior High'
有时可能想分解出某些值然后丢弃它们。在分解时,不能只是指定一个单独的*,但是可以使用几个常用来表示待丢弃值的变量名,比如_或者ign(ignored)。例如:
>>> record=('ACME',50,123.45,(12,18,2012))
>>> name,*_,(*_,year)=record
>>> name
'ACME'
>>> year
2012
1.3 保存最后N个元素
问题:希望在迭代或是其他形式的处理过程中对最后几项记录做一个有限的历史记录统计。
解决方案:
(1)collection库介绍
Python拥有一些内置的数据类型,比如str, int, list, tuple, dict等, collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型:
1.namedtuple: 生成可以使用名字来访问元素内容的tuple子类
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
此处使用双端队列deque。下面的代码对一系列文本行做简单的文本匹配操作,当发现有匹配时就输出当前的匹配行以及最后检查过的N行文本。
from collections import deque
def search(lines,pattern,history=5):
previous_lines=deque(maxlen=history)
for line in lines:
if pattern in line:
yield line,previous_lines
previous_lines.append(line)
if __name__=='__main__':
with open('test.txt') as f:
for line,previouslines in search(f,'python',5):
for pline in previouslines:
print(pline,end=' ')
print(line,end=' ')
print('-'*20)
讨论:
当编写搜索某项记录的代码时,通常会用到含有yield关键字的生成器函数。这将处理搜索过程的代码和使用搜索结果的代码成功解耦开来。
*deque(maxlen=N)*创建了一个固定长度的队列。当有新记录加入而队列已满时会自动移除最老的那条记录。例如:
>>> 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)
队列这种解决方案优雅且运行速度快。
若不指定队列的大小,可得到一个无界限队列,可在两段执行添加和删除操作。例如:
>>> q=deque()
>>> q.append(1)
>>> q.append(2)
>>> q.append(3)
>>> q
deque([1, 2, 3])
>>> q.appendleft(4)
>>> q
deque([4, 1, 2, 3])
>>> q.pop()
3
>>> q
deque([4, 1, 2])
>>> q.popleft()
4
>>> q
deque([1, 2])
从队列两端添加或弹出元素的复杂度都是O(1)。这和列表不同,当从列表头部插入或移除元素是,列表的复杂度为O(N)