my_list = ['a','b','c']
for idx,val in enumerate(my_list):
print(idx,val)
0 a
1 b
2 c
也可以传入一个可选的开始参数
for idx, val in enumerate(my_list,1):
print(idx,val)
1 a
2 b
3 c
这种操作在遍历文件时想在错误文件中使用行号定位时很有用
defparse_data(filename):with open(filename) as f:
for lineno, line in enumerate(f,1):
fields = line.split()
try:
count = int(fields[1])
passexcept ValueError as e:
print('line {}:parse error:{}'.format(lineno,e))
注意:
data = [(1,2),(3,4),(5,6),(7,8)]
for n,(x,y) in enumerate(data):
print(n,':',(x,y))
0 : (1, 2)
1 : (3, 4)
2 : (5, 6)
3 : (7, 8)
# 错误的for n,x,y in enumerate(data):
print(n,x,y)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-49-e9ca5f47e3c4> in <module>()
1 # 错误的
----> 2 for n,x,y in enumerate(data):
3 print(n,x,y)
ValueError: not enough values to unpack (expected 3, got 2)
4.11同时迭代多个序列
问题:想要同时迭代多个序列,每次从每个序列中选取一个元素
方案:使用zip()函数
a = [1,2,3,4]
b = ['a','b','c','d']
c = ['x','y','z']
for x,y in zip(a,b):
print(x,':',y)
a = [1,2,3]
b = ['a','b','c']
c = [10,20,30]
for i in zip(a,b,c):
print(i)
(1, 'a', 10)
(2, 'b', 20)
(3, 'c', 30)
zip()会返回一个迭代器,如果想要将值存储在列表中,可以使用list()函数
zip(a,b)
<zip at 0x999df0>
list(zip(a,b))
[(1, 'a'), (2, 'b'), (3, 'c')]
4.12 不同集合上元素的迭代
问题:想要在多个对象上执行相同的操作,但是这些对象在不同的容器上
方案:使用itertools.chain()
chain()函数接收一个可迭代对象列表作为输入,返回一个迭代器
from itertools import chain
a = [1,2,3]
b = ['a','b','c']
for x in chain(a,b):
print(x,end=' ')
1 2 3 a b c
也可以先将可迭代对象合并,但是效率很低,占用内存
for i in a+b:
print(i,end=' ')
1 2 3 a b c
4.13创建数据处理管道
问题:如何以数据管道的方式迭代处理数据
方案:使用生成器函数
yield from语句,它将yield操作代理到父生成器上去。yield from it 简单的返回生成器it做产生的所有值
import os,fnmatch,gzip,bz2,re
defgen_find(filepat,top):'''find all filenames in a directory tree that match a shell wildcard pattern'''for path, dirlist, filelist in os.walk(top):
for name in fnmatch.filter(filelist,filepat):
yield os.path.join(path,name)
defgen_opener(filenames):'''open a sequence of files one at a time producing a file object.
the file is closed immediately when proceeding to the next iteration
'''for filename in filenames:
if filename.endswith('.gz'):
f = gzip.open(filename,'rt')
elif filename.endswith('.bz2'):
f = bz2.open(filename,'rt')
else:
f = open(filename,'rt')
yield f
f.close()
defgen_concatenate(iterators):'''chain a sequence of iterator together into a single sequence'''for it in iterators:
yieldfrom it
defgen_grep(pattern,lines):'''look for a regex pattern in a sequence of lines'''
pat = re.compile(pattern)
for line in lines:
if pat.search(line):
yield line
4.14展开嵌套的序列
问题:如何将一个嵌套多层的序列展开成一个单层列表
方案:编写一个包含yield from 语句的递归生成器
from collections import Iterable
defflatten(items,ignore_type = (str,bytes)):for x in items:
'''isintance()用来检查某个元素是否是可以迭代的
isintance(x,ignor_type)用来将字符串和字节排除在可迭代对象之外,
防止将一个字符串拆分成单个字符
'''if isinstance(x,Iterable) andnot isinstance(x,ignore_type):
yieldfrom flatten(x)
else:
yield x
items = [1,2,[3,4,[5,6],7],8]
for x in flatten(items):
print(x,end=' ')
1 2 3 4 5 6 7 8
items = ['Dave','Paula',['Thomans','Levis']]
for x in flatten(items):
print(x,end=' ')
Dave Paula Thomans Levis
yield from 在你想在生成器中调用其它生成器作为子例程时很有用,如果你不想使用它,需要写额外的for循环
from collections import Iterable
defflatten(items,ignore_type = (str,bytes)):for x in items:
if isinstance(x,Iterable) andnot isinstance(x,ignore_type):
for i in flatten(x):
yield i
else:
yield x
4.15顺序迭代合并后的排序迭代对象
问题:有一系列排序序列,想将它们合并后得到一个排序序列并迭代遍历
方案:heapq.merge()
import heapq
a = [1,4,5,7]
b = [2,6,10,13]
for c in heapq.merge(a,b):
print(c,end=' ')
1 2 4 5 6 7 10 13
4.16 迭代器代替while无限循环
问题:使用迭代器代替while
方案:一种常见的IO操作程序如下
CHUNKSIZE = 8192defreader(s):whileTrue:
data = s.recv(CHUNKSIZE)
if data == b'':
break#process_data(data)
使用iter()代替
defreader2(s):for chunk in iter(lambda:s.recv(CHUNKSIZE),b''):
pass#process_data(data)