迭代器和生成器

迭代器和生成器

1. 可迭代对象

 1 # 迭代
 2     迭代即更新换代 每次的更新都必须依赖于上一次的结果
 3     
 4 '''迭代其实给我们提供了一种不依赖索引取值的方式'''
 5 
 6 # 可迭代对象
 7     内置有__iter__方法的都称之为可迭代对象    
 8         内置的意思是可以通过点的方式直接查看到的
 9     """
10     针对双下滑线开头 双下滑线结尾的方法 最为专业标准的读法为
11         双下方法名
12         
13     面向对象的时候为了与隐藏变量区分开
14     """
15  
16 # n = 1
17 # while True:
18 #     n+=1
19 #     print(n)
20 
21 # l = [11,22,33,44,55,66]
22 # n = 0
23 # while n < len(l):
24 #     print(l[n])
25 #     n += 1
26 
27 i = 12  # 没有
28 f = 11.11  # 没有
29 s = 'jason'  #
30 l = [111,22,33,4]  #
31 d = {'username':'jason','pwd':123}  #
32 t = (11,22,33)  #
33 se = {11,22,33}  #
34 b = True  # 没有
35 # file = open(r'a.txt','w',encoding='utf8')
36 """
37 含有__iter__的有
38     字符串 列表 字典 元组 集合 文件对象
39 上述通常为可迭代对象
40 """
41 print(d)
42 print(d.__iter__())  # 等价于调用了一个内置方法 d.get()
43 print(iter(d))
44 print(d.__len__())
45 print(len(d))
46 """
47 可迭代对象调用__iter__方法会变成迭代器对象(老母猪)
48 
49 __iter__方法在调用的时候还有一个简便的写法iter()
50     一般情况下所有的双下方法都会有一个与之对应的简化版本 方法名()
51 """

2. 迭代器对象

 1 """
 2 迭代器对象
 3     即含有__iter__方法 又含有__next__方法
 4 如何生成迭代器对象
 5     让可迭代对象执行__iter__方法
 6 
 7 文件对象本身即是可迭代对象又是迭代器对象
 8 迭代器对象无论执行多少次__iter__方法 还是迭代器对象(本身)
 9 
10 迭代器给我们提供了不依赖于索引取值的方式
11 """
12 i = 12  # 没有
13 f = 11.11  # 没有
14 s = 'jason'  #
15 l = [111,222,333,444]  #
16 d = {'username':'jason','pwd':123}  #
17 t = (11,22,33)  #
18 se = {11,22,33}  #
19 b = True  # 没有
20 file = open(r'a.txt','w',encoding='utf8')
21 
22 # res = s.__iter__()  # 转成迭代器对象
23 # print(res.__next__())  # 迭代器对象执行__next__方法其实就是在迭代取值(for循环)
24 # print(res.__next__())
25 # print(res.__next__())
26 # print(res.__next__())
27 # print(res.__next__())
28 
29 
30 # res = d.__iter__()  # 转成迭代器对象
31 # print(res.__next__())  # 迭代器对象执行__next__方法其实就是在迭代取值(for循环)
32 # print(res.__next__())
33 # print(res.__next__())  # 取完元素之后再取会"报错"
34 
35 # 易错
36 # print(d.__iter__().__next__())  # username
37 # print(d.__iter__().__next__())  # username
38 # print(d.__iter__().__next__())  # username
39 # print(d.__iter__().__next__())  # username
40 # print(d.__iter__().__next__())  # username
41 # print(d.__iter__().__next__())  # username

3. 生成器

  3.1 生成器对象

 1 """
 2 生成器其实就是自定义迭代器
 3 """
 4 # 定义阶段就是一个普通函数
 5 def my_ge():
 6     print('first')
 7     yield 123,222,333
 8     print('second')
 9     # yield 456,444,555
10 """
11 当函数体内含有yield关键字 那么在第一次调用函数的时候
12 并不会执行函数体代码 而是将函数变成了生成器(迭代器)
13 """
14 # 调用函数:不执行函数体代码 而是转换为生成器(迭代器)
15 # res = my_ge()
16 # ret = res.__next__()  # 每执行一个__next__代码往下运行到yield停止 返回后面的数据
17 # print(ret)
18 # ret = res.__next__()  # 再次执行__next__接着上次停止的地方继续往后 遇到yield再停止
19 # print(ret)

  3.2 yield传值

1 def eat(name):
2     print('%s 准备干饭!!!'%name)
3     while True:
4         food = yield
5         print('%s 正在吃 %s' % (name, food))
6 res = eat('jason')  # 并不会执行代码 而是转换成生成器
7 res.__next__()
8 res.send('肉包子')
9 res.send('盖浇饭')

  3.3 yield和return的对比

1 yield
2     1.可以返回值(支持多个并且组织成元组)
3     2.函数体代码遇到yield不会结束而是"停住"
4     3.yield可以将函数变成生成器 并且还支持外界传值
5 return
6     1.可以返回值(支持多个并且组织成元组)
7     2.函数体代码遇到return直接结束

  3.4 生成器表达式

l = [11, 22, 33, 44, 55, 66, 77, 88, 99]
# res = [i+1 for i in l if i!=44]
# print(res)

# res1 = (i+1 for i in l if i!=44)
"""
生成器表达式内部的代码只有在迭代取值的时候才会执行
"""
# print(res1.__next__())
# print(res1.__next__())
# print(res1.__next__())
"""
    迭代器对象 生成器对象 我们都可以看成是"工厂"
    只有当我们所要数据的时候工厂才会加工出"数据"
        上述方式就是为了节省空间
"""
# 求和
def add(n, i):
    return n + i
# 调用之前是函数 调用之后是生成器
def test():
    for i in range(4):
        yield i
g = test()  # 初始化生成器对象
for n in [1, 10]:
    g = (add(n, i) for i in g)
    """
    第一次for循环
        g = (add(n, i) for i in g)
    第二次for循环
        g = (add(10, i) for i in (add(10, i) for i in g))
    """
res = list(g)
print(res)

#A. res=[10,11,12,13]
#B. res=[11,12,13,14]
#C. res=[20,21,22,23]
#D. res=[21,22,23,24]

 

posted @ 2021-11-22 15:33  XX_Bb  阅读(45)  评论(0编辑  收藏  举报