迭代器
迭代器的定义:
- 迭代器是访问可迭代对象的工具
- 迭代器是指用iter(obj)函数返回的对象(或实例)
- 迭代器可以用next(it)函数获取可迭代对象的数据
用在迭代器的函数有两个,分别是iter和next
在了解迭代器之前先了解一下什么是可迭代对象:
- 表面来看,只要可以用 for…in…进行遍历的对象就是可迭代对象
例如:list列表、tuple元组、str字符串等都是可迭代对象
- iter(iterable)从可迭代对象中返回一个迭代器,iterable必须是能够提供一个迭代器的对象
- next(iterator)从迭代器iterator中获取下一个记录,如果无法获取了,则触发stopIterator异常
说明:
- 迭代器只能往前取值,不会后退
- 用iter函数返回的是一个可迭代对象的迭代器
举个栗子:
L = [1, 3, 5, 7] # 或 L = (1, 3, 5, 7)等可迭代对象都行
it = iter(L) # 让L提供一个能访问自己的迭代器
print(ext(it)) # 1 从迭代器中取值,让迭代器去获取L中的一个元素
print(ext(it)) # 3
print(ext(it)) # 5
print(ext(it)) # 7
print(ext(it)) # StopIteraotr 异常
当然这只是为了更直观的观察是怎么打印的
也可以使用循环遍历出结果
那么就引出了迭代的用处:
用迭代器可以依次访问可迭代对象的数据
示例:
L = [1, 3, 5, 7]
for i in L:
print(i) # 1 3 5 7
以下用迭代器来访问L列表中的元素
L = [1, 3, 5, 7]
it = iter(L) # 先拿到迭代器用it绑定
while True:
x = next(it) # 获取一个数据并绑定x
print(x) # 1 3 5 7
生成器
能够动态提供数据的对象,生成器对象也是可迭代对象,生成器也有两种表示方式:函数和表达式
函数:含有yield语句的函数,此函数被调用将返回一个生成器对象
注:yield翻译成产生(或生成)
yield用于def 函数中,目的就是将此函数作为生成器函数使用
yield用来生成数据,供迭代器和next(it)函数使用
生成器函数的声明:
- 生成器函数调用return语句会触发一个StopIterator异常
举个小栗子:
题目:写一个生成器函数myeven(start, stop)
用来生成start到stop(不包含stop)结束的偶数并 存放在列表中
def myeven(start, stop):
# 方法一
# i = start + 1
# while i < stop:
# yield i
# i += 2
# 方法二
# while start < stop:
# if start % 2 == 0:
# yield start
# start += 1
# 方法三
for i in range(start + 1, stop, 2):
yield i
for x in myeven(1, 10):
print(x)
L = [x ** 2 for x in myeven(1, 20)]
print(L)
解释以上代码:
只解释方法三即可:
先说说输入与输出:
在myeven(start, stop)中,如果start = 10,stop = 20,则输出的应该是10,12,14,16,18,也就是输出start到stop之间的偶数,但是不包括stop
再说说生成器函数
生成器是现用现生成,即可以理解为,你让我去干一件事,我干完就完事,你再让我干另一件事,我再去干,而不是说你给我一个清单让我一次性的做完清单上的事。
图片上的函数外的for循环是多次调用myeven函数,把1和10传进去,然后函数内部的for循环则循环生成一个数,但每次循环都会返回给外层循环打印出这个数,然后继续内部循环,再返回,…,这样一直调用到不满足条件为止
生成器表达式:
语法:
(表达式 for 变量 in 可迭代对象 [if 真值表达式])
作用:
用推导式形式创建一个新的生成器
说明:
if 子句可以省略
示例:
gen = (x**2 for x in range(1, 5))
it = iter(gen)
print(next(it)) # 1
print(next(it)) # 4
print(next(it)) # 9
print(next(it)) # 16
print(next(it)) # StopIteration
生成器表达式和列表推导式的区别:
# 列表推导式
L = [2, 3, 5, 7]
L2 = [x**2+1 for x in L] # 已经生成列表
it = iter(L2)
print((next(it))) # 5
L[1] = 30 # 再改变L的值也不影响L2列表
print(next(it)) # 10
# 生成器表达式
L = [2, 3, 5, 7]
gen = (x**2+1 for x in L) # 现用现生成,每次用只生成一个对应的值
it = iter(gen)
print((next(it))) # 5
L[1] = 30 # 由于不是生成的列表,每次只生成一个值,所以这是先给变原列表对应的值,然后再做运算
print(next(it)) # 901
总结:生成器推导式是现用现生成,列表推导式是一次性生成静态数据
迭代工具函数:
生成一个个性化的可迭代对象
函数:
zip(iter1, [, iter[..]])
返回一个zip对象,此对象用于生成元组,此元组的每个数据来源于参数中的可迭代对象,当最小的可迭代对象不再提供数据时迭代结束
enumerate(iterable [, start])生成带索引的枚举对象,返回的迭代类型为索引-值对象(index-value)对,默认索引从0开始,也可以用start指定
zip示例:
numbers = [10086, 10010, 10000, 95588]
names = ['中国移动', '中国联通', '中国电信']
for t in zip(numbers, names):
print(t)
for No, number, name in zip(range(1, 100), numbers, names):
print('序号', No, name, '的客服电话是:', number)
打印结果:
(10086, '中国移动')
(10010, '中国联通')
(10000, '中国电信')
序号 1 中国移动 的客服电话是: 10086
序号 2 中国联通 的客服电话是: 10010
序号 3 中国电信 的客服电话是: 10000
enumerate示例:
names = ['中国移动', '中国联通', '中国电信']
for t in enumerate(names):
print(t)
打印结果:
#(0, '中国移动')
#(1, '中国联通')
#(2, '中国电信')
改变序号:
for t in enumerate(names, 101):
print(t)
打印结果:
#(101, '中国移动')
#(102, '中国联通')
#(103, '中国电信')
不得不说zip是个很实用的家伙,据说用的挺多的,简单举个栗子:
numbers = [10086, 10010, 10000, 95588]
names = ['中国移动', '中国联通', '中国电信']
print(list(zip(numbers, names)))
print(tuple(zip(numbers, names)))
print(dict(zip(numbers, names)))
print(set(zip(numbers, names)))
打印结果:
[(10086, '中国移动'), (10010, '中国联通'), (10000, '中国电信')]
((10086, '中国移动'), (10010, '中国联通'), (10000, '中国电信'))
{10086: '中国移动', 10010: '中国联通', 10000: '中国电信'}
{(10086, '中国移动'), (10000, '中国电信'), (10010, '中国联通')}
尤其是字典,省去了不少功夫,一下搞定
本章暂时到这,是不是莫名的就结束了?没办法啦。。。