| title | date | tags | categories | description | ||
|---|---|---|---|---|---|---|
|
迭代器与生成器
|
2019-09-23 12:25:39 -0700
|
|
|
python中的迭代器与生成器
|
迭代器
迭代是访问集合元素的一种方式,迭代器是一种可以记住遍历的位置的对象,从集合的第一个元素开始访问知道所有的元素访问完结束
查看是否可以迭代
- 可迭代的对象可以使用
isinstance验证与Iterable的关系,返回True则可以迭代 - 迭代器可以使用
isinstance验证与Iterator的关系,返回True则可以迭代
from collections import Iterable
print(isinstance([11, 22], Iterable))
定义可以迭代的类
- 如果想让创建的对象可以迭代,必须实现
__iter__()方法,且需要返回一个迭代器
返回的迭代器也是一个对象,这个对象要包含
__iter__()方法和__next__(),方法,其中__next__()方法的返回值就是迭代的内容可以重新写一个迭代器的类,用于返回值 可以直接返回
self,并在本类中实现__next__()
- 两个类实现迭代
class my_iter():
def __init__(self):
self.names = list()
def my_iterator(self, name):
self.names.append(name)
def __iter__(self):
# 返回一个迭代器对象
return my_itor(self)
class my_itor():
def __init__(self, obj):
self.obj = obj
self.current_num = 0
def __iter__(self):
pass
def __next__(self):
if self.current_num < len(self.obj.names):
ret = self.obj.names[self.current_num]
self.current_num += 1
return ret
else:
# 超过容量抛出StopIteration来终止迭代
raise StopIteration
my_iterator = my_iter()
my_iterator.my_iterator("张三")
my_iterator.my_iterator("李四")
my_iterator.my_iterator("王五")
for temp in my_iterator:
print(temp)
运行结果
张三
李四
王五
实现了迭代功能
- 一个类实现迭代
class my_iter():
def __init__(self):
self.names = list()
self.current_num = 0
def my_iterator(self, name):
self.names.append(name)
def __iter__(self):
# 返回自身,会自动调用__next__()方法
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
# 超过容量抛出StopIteration来终止迭代
raise StopIteration
my_iterator = my_iter()
my_iterator.my_iterator("张三")
my_iterator.my_iterator("李四")
my_iterator.my_iterator("王五")
for temp in my_iterator:
print(temp)
运行结果
张三
李四
王五
也实现了迭代功能
- 迭代器在类型转换中的作用
my_list = [ 11, 22, 33 ]
my_tuple = tuple(my_list)
print(my_tuple)
运行结果
(11, 22, 33)
实质上是先生成一个空的元组,然后调用
my_list中的迭代方法,向my_tuple中添加内容
iter()和next()方法
iter()用于获取可迭代对象的迭代器,实质上是调用了可迭代对象的__iter__()方法next()方法用于获取迭代对象的下一条数据,迭代完成后抛出StopIteration的异常终止迭代
>>> l1 = [11, 22, 33]
>>> l1_iter = iter(l1)
>>> next(l1_iter)
11
>>> next(l1_iter)
22
>>> next(l1_iter)
33
>>> next(l1_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
生成器
- 生成器是一种特殊的迭代器
创建生成器
方法一
- 将列表生成式的
[]换成()
>>> l = [x for x in range(5)]
>>> l
[0, 1, 2, 3, 4]
>>> g = (x for x in range(5))
>>> g
<generator object <genexpr> at 0x7f924b6088d0>
方法二
- 使用
yield创建 yield会返回它后面的值,并将程序停留于此,等待下一次调用从当前位置开始执行- 示例
# 输出斐波纳奇数列
def create_num(all_num):
print("---1---")
a, b = 0, 1
current_num = 0
while current_num < all_num:
print("---2---")
# 如果一个函数中有yield语句,那么这个就不再是函数,而是一个生成器的模板
yield a
print("---3---")
a, b = b, a+b
current_num += 1
print("---4---")
# 如果在调用create_num的时候,发现这个函数中有yield,那么此时不是调用函数,而是创建一个生成器对象
obj = create_num(5)
for num in obj:
print(num)
运行结果
---1---
---2---
0
---3---
---4---
---2---
1
---3---
---4---
---2---
1
---3---
---4---
---2---
2
---3---
---4---
---2---
3
---3---
---4---
可见只输出了一次
---1---,而当第二次循环的时候没有进行初始化,直接在while循环中的yield下面继续执行,即yield返回后面的a后,停留在当前位置,等待下一次执行
另外,当使用同一个模板创建了多个生成器时,相互之间互不影响
- 当生成器执行完成后有返回值时,可以使用异常获取
def create_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
yield a
a, b = b, a+b
current_num += 1
return "遍历结束"
obj = create_num(5)
while True:
try:
# 使用next()启用生成器
ret = next(obj)
print(ret)
except Exception as e:
# 获取返回值
print(e.value)
break
运行结果
0
1
1
2
3
遍历结束
启动生成器
使用next()启动
上面的例子中都是使用
next()启动的,这里不再介绍
使用send()启动
send()中可以填入参数作为yield执行后的返回值
def create_num(all_num):
a, b = 0, 1
current_num = 0
while current_num < all_num:
res = yield a
print(res)
a, b = b, a+b
current_num += 1
return "遍历结束"
obj = create_num(5)
ret = next(obj)
print(ret)
while True:
try:
ret = obj.send("你好")
print(ret)
except Exception as e:
print(e.value)
break
运行结果
0
你好
1
你好
1
你好
2
你好
3
你好
遍历结束
可见,
send()将"你好"作为参数传递给了yield执行后的结果res,并且,它是下一次进入函数才传递的,这点可以从结果中先输出0(print(ret)),后输出你好(print(res))可以看出来 因此,send()如果作为第一次启动生成器时,必须使用obj.send(None),即不传入参数,或使用next(obj)来第一次启动

被折叠的 条评论
为什么被折叠?



