迭代器与生成器的概念
- 先搞清楚概念什么
- 迭代器
很多容器比如list, tuple, dict, set等都可以使用for 循环,for语句会调用容器对像中有iter()函数,该函数返回一个next方法的迭代对像, 在python 中,只要定义了一个next方法,其实就是一个迭代器, 比如列表,字典,集合,字符串等
用for取元素,遍历过程可以称为迭代,如果不想使用for,可以就可以使用iter(),next(), 没有元素后next()会引发StopIteration异常
s = 'abc'
for i in s:
print(i)
ss = 'abc'
it = iter(ss) # 调用容器的iter函数
print(it) # <str_iterator object at 0x110441410>
print(next(it)) #a 使用next()内置函数来调用__next__()方法
print(next(it)) #b
print(next(it)) #c
print(next(it)) #StopIteration 引发异常
- 生成器
列表数据如果太大, 比如一个列表包含100W的元素而我们只需要前面几个元素,那么该列表的空间是不是就浪费掉了呢? 为了优化这种问题,可以考虑下假如列表元素可以按照某算法推算出来, 那么我们是不是可以在循环过程中不断推算出后续的元素呢,这样就不需要再创建完整的list, 从而节省了空间, 这种方式其实就是生成器,与迭代器类似于包含与被包含的关系,生成器就是一种迭代器. 不过在迭代过程中只能迭代一次,因为它们并不是把所有值存在内存中,而是在运行时才会生成值啊.
迭代器并不返回一个值,而是yield一个值
def generat(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
for char in generat('golf'):
print(char)
- 生成器表达式
print(sum(i*i for i in range(10))) #285
x = [1,2,3]
y = [4,5,6]
print(sum(x*y for x,y in zip(x,y)))
跳过可迭代对象的开始部分
- 想遍历一个可迭代对像,但对刚开始的一些元素不感兴趣,比如/etc/passwd中的##号,这个时候可以使用
itertools.dropwhile()
函数
from itertools import dropwhile
with open('/etc/passwd') as f:
# for line in f:
# print(line, end= '')
for line in dropwhile(lambda line: line.startswith('#'),f ): #dropwhile()接受一个函数或者可迭代对像
print(line, end='')
排列组合的迭代
- eg: 想迭代遍历一个集合中元素的所有可能的排列或者组合,可以使用itertools模块中的方法
from itertools import permutations
items =['a','b', 'c']
# 打乱集合中元素排列顺序生成一个元组
for p in permutations(items):
print(p)
# 输出
# ('a', 'b', 'c')
# ('a', 'c', 'b')
# ('b', 'a', 'c')
# ('b', 'c', 'a')
# ('c', 'a', 'b')
# ('c', 'b', 'a')
for pP in permutations(items,2): #得到指定长度的所有排列
print(pP)
# ('a', 'b')
# ('a', 'c')
# ('b', 'a')
# ('b', 'c')
# ('c', 'a')
# ('c', 'b')
# combinations 可得到输入集合中元素的所有的组合
for c in combinations(items,3):
print(c) #('a', 'b', 'c')
for cc in combinations(items,2):
print(cc) # ('a', 'b')
#('a', 'c')
#('b', 'c')
序列上索引值迭代
- 想在迭代一个序列的同时跟踪正在被处理的元素索引,可以使用
enumerate()
函数
my_list = ['a','b','c']
for idx, val in enumerate(my_list):
print(idx,val)
# 0 a
# 1 b
# 2 c
#如果你想将一个文 件中出现的单词映射到它出现的行号上去,可以很容易的利用 enumerate() 来完成
word_summary = defaultdict(list)
# 每个单词对应一个Key,值为出现的次数,当然 下面分隔单词的情况具体还要看文本是什么样子, 使用正则区分会比较好
with open('/Users/yjoqm/billboard.txt', 'r') as f:
lines = f.readlines()
for idx, line in enumerate(lines):
# words = [w.strip().lower() for w in line.strip()]
words = [w for w in line.strip().split(' ')]
print(words)
for word in words:
word_summary[word].append(idx)
print(word_summary)
# defaultdict(<class 'list'>, {'{': [0, 3], '"code":': [1], '0,': [1], '"time":': [2], '1559136497,': [2], '"data":': [3]
同时迭代多个序列
- 想同时迭代多个序列,每次分别从一个序列中取一个元素,使用zip()
xpts =[1, 5,4, 2,10,7]
ypts =[101, 78, 37,15, 62,99]
for x,y in zip(xpts, ypts):
print(x,y)
#itertools.zip_longest()为zip函数的补充,可以设置缺失字段的默认值,比如 zip_longest(a,b,fillvalue=0)
# 可以zip打包,然后使用dict(zip())转换成字典进行处理。