1.迭代器 Iterator
迭代器是指用
iter(iterable)
函数返回的对象(实例), 可以记住遍历的位置的对象, 间接访问可迭代对象的一种方式。
迭代器可以用
next(Iterator)
函数依次获取可迭代对象的值, 表示一个惰性计算的序列, 迭代器只能往前取值,不会后退, 也可以用 for 语句遍历;
- iter()、next()函数
1. iter(iterable) 从可迭代对象中返回一个迭代器Iterator,iterable必须是一个可迭代对象
2. next(Iterator) 从迭代器Iterator 中获取下一个记录,如果无法获取下一条记录,则触发StopIteration,异常来通知调用者已无数据可提供
- 可迭代对象
集合数据类型:
str、list、tuple、dict、set、frozenset
函数返回值:
range(), map(), filter(), sorted(), zip(), enumerate()
注:凡是可作用于for循环的对象都是Iterable类型, 集合数据类型如list、dict、str等是Iterable, 但不是Iterator,不过可以通过iter()函数获得一个Iterator对象
L = [1,3,5,7,9] # L为可迭代对象
L.__next__()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-13-a270d7e520f0> in <module>
1 L = [1,3,5,7,9] # L为可迭代对象
----> 2 L.__next__()
AttributeError: 'list' object has no attribute '__next__'
L = [1,3,5,7,9] # L为可迭代对象
next(L)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-1dc6ff802149> in <module>
1 L = [1,3,5,7,9] # L为可迭代对象
----> 2 next(L)
TypeError: 'list' object is not an iterator
L = [1,3,5,7,9] # L为可迭代对象
it = iter(L) # 变量it 绑定迭代器
v = next(it) # v 绑定
print(v)
print(it.__next__())
print(next(it))
print(next(it))
print(next(it))
print(next(it))
1
3
5
7
9
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-15-658214e2d174> in <module>
7 print(next(it))
8 print(next(it))
----> 9 print(next(it))
StopIteration:
- for循环本质上就是通过不断调用next()函数实现的
for x in [1, 2, 3, 4, 5]:
print(x)
# 完全等价于:
it = iter([1, 2, 3, 4, 5])
while True:
try:
# 获得下一个值:
print(next(it))
except StopIteration:
# 遇到StopIteration就退出循环
break
1
2
3
4
5
1
2
3
4
5
2. 生成器:Generator(python2.5 之后)
生成器是指能够动态提供数据的对象,只用在调用的时候才会生成相应的数据,只记录当前数据,生成器对象也是迭代器对象,当迭代超出范围后,产生一个StopIteration
- 生成器有两种
只能用for 语句、next 函数、生成器属性取值,取值时生成器才会生成要用到的数据
1、生成器函数
2、生成器表达式
注:生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
1. 生成器函数:
含有yield 语句的函数是生成器函数,此函数调用将返回一个生成器对象 yield 翻译为生成、产生
- yield语句格式:
yield 表达式
- 说明:
yield 用于def 函数中,目的是将此函数作为生成器函数使用
yield 用来生成数据,此数据提供给迭代器的next(generator) 函数使用
yield 记住当前执行环境暂停函数,并返回数据给调用处,再次取数据时执行回到yield 语句处向下执行
练习:写一个生成器函数,用于生成n 个斐波那契数,n 以参数的形式传入
def fib(max):
n, a, b = 0, 0, 1
while n < max:
# print(b)
yield b
a, b = b, a + b
n = n + 1
# return "done"
g = fib(6)
while True:
try:
x = next(g)
print("g", x)
except Exception as e:
print("Generator return value:", e.value)
break
g 1
g 1
g 2
g 3
g 5
g 8
Generator return value: None
- 生成器函数说明:
生成器函数的调用将返回一个可迭代对象
生成器函数调用return 语句,当迭代超出范围后,产生一个StopIteration 异常后加return 的值(如:StopIteration: done)
生成器函数每次用next() 函数取值时才会执行,遇到yield语句后将停止执行,并返回数据
2. 生成器表达式:generator expression
语法:(表达式 for 变量 in 可迭代对象 [if 真值表达式]) 注:[]内的if部分可以省略,形式很像列表生成式,只是把中括号改成了小括号
作用:用推导式的形式生成一个新的生成器,可以用生成器的属性 .__next__() 取值
a = (x*2 for x in range(5)) # 使用生成器表达式来创建一个生成器
a
<generator object <genexpr> at 0x10a897228>
print(next(a), a.__next__())
0 2
s = iter(a)
s
<generator object <genexpr> at 0x10a897228>
print(s.__next__(), next(s))
4 6
a.__next__()
a.__next__()
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-11-5e73900f2c53> in <module>
1 a.__next__()
----> 2 a.__next__()
StopIteration:
- 生成器表达式和列表推导式的区别:
1、生成器表达式中产生的数据是现用现生成,不记住之前生成的数据,也不能使用已经生成过的数据,当迭代超出范围后,产生一个StopIteration
2、列表推导式会一次性生成所有数据
- 生成器的并发
import time
def consumer(name):
print("%s 准备吃包子!" % name)
while True:
baozi = yield
print("包子[%s] 来了,被[%s] 吃了!" % (baozi, name))
def producer(name):
c = consumer("A")
c2 = consumer("B")
y = c.__next__()
y1 = c2.__next__()
print("准备做包子!", y, y1)
for i in range(10):
time.sleep(1)
print("做了2 个包子")
c.send(i)
c2.send(i)
producer("庄")
A 准备吃包子!
B 准备吃包子!
准备做包子! None None
做了2 个包子
包子[0] 来了,被[A] 吃了!
包子[0] 来了,被[B] 吃了!
做了2 个包子
包子[1] 来了,被[A] 吃了!
包子[1] 来了,被[B] 吃了!
做了2 个包子
包子[2] 来了,被[A] 吃了!
包子[2] 来了,被[B] 吃了!
做了2 个包子
包子[3] 来了,被[A] 吃了!
包子[3] 来了,被[B] 吃了!
做了2 个包子
包子[4] 来了,被[A] 吃了!
包子[4] 来了,被[B] 吃了!
做了2 个包子
包子[5] 来了,被[A] 吃了!
包子[5] 来了,被[B] 吃了!
做了2 个包子
包子[6] 来了,被[A] 吃了!
包子[6] 来了,被[B] 吃了!
做了2 个包子
包子[7] 来了,被[A] 吃了!
包子[7] 来了,被[B] 吃了!
做了2 个包子
包子[8] 来了,被[A] 吃了!
包子[8] 来了,被[B] 吃了!
做了2 个包子
包子[9] 来了,被[A] 吃了!
包子[9] 来了,被[B] 吃了!
3. 迭代工具函数
迭代工具函数的作用是生成一个个性化的可迭代对象
- zip(iter[, iter,…]) 返回一个zip对象,此对象用于生成元组,此元组的个数由最小的可迭代对象决定
numbers = [10086, 10000, 10010, 95588]
names = ['中国移动', '中国电信', '中国联通']
for x in zip(numbers, names):
print(x)
(10086, '中国移动')
(10000, '中国电信')
(10010, '中国联通')
- enumerate(iterator[, start]), 生成带索引的枚举对象,返回迭代类型为索引-值对(index, value)的元组,默认索引从零开始,也可以指定start
numbers = [10086, 10000, 10010, 95588]
names = ['中国移动', '中国电信', '中国联通']
# L = [(0, '中国移动'), (1, '中国电信'), (2, '中国联通')]
for x in enumerate(names):
print(x)
# 扩展
for no, n in enumerate(names): # (等同于序列赋值)
print(no, " ----->", n)
(0, '中国移动')
(1, '中国电信')
(2, '中国联通')
0 -----> 中国移动
1 -----> 中国电信
2 -----> 中国联通
练习:写一个程序,输入任意行文字,当输入空行时结束输入打印带有行号的输出结果
请输入:hello
请输入:world
请输入:bye
请输入:<回车>
输出如下:
第1行:hello
第2行:world
第3行:bye
input_words = []
while True:
input_word = input("请输入:")
if not input_word:
break
input_words.append(input_word)
for no, word in enumerate(input_words):
print("第%s行:%s" % (no+1, word))
请输入:hello
请输入:world
请输入:bye
请输入:
第1行:hello
第2行:world
第3行:bye
练习:用生成器函数,生成素数,给出起始值为begin和终止值end,此生成器函数为
def myprimes(n, m):
for y in range(n, m+1):
for x in range(2, int(y**0.5)+1):
if y % x == 0:
break
else:
yield y
L = [x for x in myprimes(10, 20)]
print(L)
[11, 13, 17, 19]
练习: 写一个生成器函数,参数为n,生成斐波那契数列的前n个数
def fibonacci(n):
L = [1, 1]
for x in range(n - 2):
s = 0
s = (L[x] + L[x + 1])
L.append(s)
for y in L:
yield y
L = [x for x in fibonacci(7)]
print(L)
[1, 1, 2, 3, 5, 8, 13]
def fib(max):
n, a, b = 0, 0, 1
while n < max:
# print(b)
yield b
a, b = b, a + b
n = n + 1
# return "done"
g = fib(6)
while True:
try:
x = next(g)
print(x)
except Exception as e:
print("Generator return value:", e.value)
break
1
1
2
3
5
8
Generator return value: None
同名公众号:庄AC