0%

迭代器和生成器

迭代器

  • 内部含有_iter_方法和_next_方法都是迭代器
    • 可迭代对象 都可以通过内置函数 iter转换为迭代器
    • 内置函数 next 进行迭代操作,当所有数据迭代完毕后,再使用 next 迭代,会抛出异常 StopIteration
  • 使用for循环容器取值的都是可迭代的

容器就是将多个元素在一起的单元,并且,是可以迭代的,比如列表,字典,元组,字符串

  • 如下代码
1
2
3
4
5
6
7
8
# 将列表转换为一个迭代器
iter_li = iter([11,22)
# 通过next对迭代器进行迭代操作,每次可以迭代出来一个数据
s1 = next(iter_li)
print('s1:',s1)
s2 = next(iter_li) # s1 :11
print('s2:',s2) # s2 :22
s3 = next(iter_li) # StopIteration 错误

生成器

  • 是一种特殊的迭代器,具备迭代器所有的特性。但其相比与迭代器,占用的内存更少

  • 他本质上是一个函数,只不过函数的return改为了yield语句,正常的for循环语句,会不停的遍历容器的对象,然后返回(如果有return的话),当我们用yield取而代之

  • 每当函数执行时遇到yield时,他会记住此时的一个位置并挂起,等到使用__next__操作时,才由上一次挂起的位置继续执行。生成器不仅“记住”了它的数据状态,生成还记住了程序执行的位置

  • python 中定义生成器,一共有两种方式,一种是生成器表达式,另一种是生成器函数。

生成器表达式

生成器表达式的语法其实就是把列表推导式的中括号改成小括号,如下:

1
2
3
4
5
6
7
gen_ =(item for item in range(2))
print(gen_)
s1 = next(gen_)
print(s1)
next(gen_)
next(gen_) # 报错StopIteration

生成器函数

在函数中使用 yield关键字可以定义一个生成器函数

1
2
3
4
5
6
7
8
9
10
def func():
for i in range(1):
yield i

gen_list = func()
# 调用函数
gen_lsit = func()
s2 = next(gen_list)
print(s2)
next(gen_list) # 报错StopIteration

自定义类生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from collections import Iterable
from collections import Iterator
import time


class Classmate(object):
"""定义一个同学类"""

def __init__(self):
self.name = list()
self.name_num = 0

def add(self, name):
self.name.append(name)

def __iter__(self):
return self # 返回本身

def __next__(self):
if self.name_num < len(self.name):
ret = self.name[self.name_num]
self.name_num += 1
return ret

# 抛出异常,当循环后自动结束
else:
print("-------StopIteration---")
raise StopIteration


class1 = Classmate()
class1.add("张三")
class1.add("李四")
class1.add("王五")

print("判断是否是可迭代的对象:", isinstance(class1, Iterable))

print("判断是否是迭代器:", isinstance(class1, Iterator))

for name in class1:
print(name)
time.sleep(1)

# 结果为
判断是否是可迭代的对象: True
判断是否是迭代器: True
张三
李四
王五
-------StopIteration---

总结两者的区别

  • 生成器就是迭代器,反之则不是
  • 迭代器,在创建的时候已经生成(比如上面迭代器的列子),在需要的时候再去操作迭代器加载元素到内存中
  • 而生成器,本质是一个可以暂时挂起的函数,等到需要时再继续执行去生成元素,这样子,使得生成器比迭代器更省内存。