11 Day Python之迭代器&生成器

迭代器&生成器

一、可迭代的&迭代器

可迭代协议

①协议内容:内部实现了__iter__方法

②验证方法:dir()方法;使用dir()方法查看数据类型中的方法是否包含__iter__

③__iter__()方法的作用:可迭代的数据类型执行__iter__()方法后会生成一个迭代器对象

④例子:

1 print([1,2].__iter__())
2 # 结果
3 <list_iterator object at 0x1024784a8>
View Code
 1 """
 2 dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,
 3 都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,然后取差集。
 4 """
 5 #print(dir([1,2].__iter__()))
 6 #print(dir([1,2]))
 7 print(set(dir([1,2].__iter__()))-set(dir([1,2])))
 8 
 9 结果:
10 {'__length_hint__', '__next__', '__setstate__'}
11 
12 # 迭代器中多出的三个方法介绍
13 iter_l = [1,2,3,4,5,6].__iter__()
14 
15 #获取迭代器中元素的长度
16 print(iter_l.__length_hint__())
17 
18 #根据索引值指定从哪里开始迭代
19 print('*',iter_l.__setstate__(4))
20 #一个一个的取值
21 print('**',iter_l.__next__())
22 print('***',iter_l.__next__())
View Code

二、生成器

①种类:python中提供的生成器有:

  • 生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
  • 生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

②本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现) 

③特点:惰性运算,开发者自定义

④生成器函数:一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

  • 1) 生成器函数例子:
     1 import time
     2     def genrator_fun1():
     3         a = 1
     4         print('现在定义了a变量')
     5         yield a
     6         b = 2
     7         print('现在又定义了b变量')
     8         yield b
     9 
    10     g1 = genrator_fun1()
    11     print('g1 : ',g1)       #打印g1可以发现g1就是一个生成器
    12     print('-'*20)   #我是华丽的分割线
    13     print(next(g1))
    14     time.sleep(1)   #sleep一秒看清执行过程
    15     print(next(g1))
    View Code

    2) 生成器函数的好处:可以避免一次性读取数据到内存中导致内存溢出

     1 # 例子01:
     2 def produce():
     3     """生产衣服"""
     4     for i in range(2000000):
     5         yield "生产了第%s件衣服"%i
     6 
     7 product_g = produce()
     8 print(product_g.__next__()) #要一件衣服
     9 print(product_g.__next__()) #再要一件衣服
    10 print(product_g.__next__()) #再要一件衣服
    11 num = 0
    12 for i in product_g:         #要一批衣服,比如5件
    13     print(i)
    14     num +=1
    15     if num == 5:
    16         break
    17 
    18 #到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
    19 #剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
    20 
    21 # 例子02:
    22 import time
    23 def tail(filename):
    24     f = open(filename)
    25     f.seek(0, 2) #从文件末尾算起
    26     while True:
    27         line = f.readline()  # 读取文件中新的文本行
    28         if not line:
    29             time.sleep(0.1)
    30             continue
    31         yield line
    32 
    33 tail_g = tail('tmp')
    34 for line in tail_g:
    35     print(line)
    36 # 例子03:
    37 def averager():
    38     total = 0.0
    39     count = 0
    40     average = None
    41     while True:
    42         term = yield average
    43         total += term
    44         count += 1
    45         average = total/count
    46 
    47 g_avg = averager()
    48 next(g_avg)
    49 print(g_avg.send(10))
    50 print(g_avg.send(30))
    51 print(g_avg.send(5))
    52 # 例子04:
    53 def init(func):  #在调用被装饰生成器函数的时候首先用next激活生成器
    54     def inner(*args,**kwargs):
    55         g = func(*args,**kwargs)
    56         next(g)
    57         return g
    58     return inner
    59 
    60 @init
    61 def averager():
    62     total = 0.0
    63     count = 0
    64     average = None
    65     while True:
    66         term = yield average
    67         total += term
    68         count += 1
    69         average = total/count
    70 
    71 g_avg = averager()
    72 # next(g_avg)   在装饰器中执行了next方法
    73 print(g_avg.send(10))
    74 print(g_avg.send(30))
    75 print(g_avg.send(5))
    View Code

    3) yield from

     1 def gen1():
     2     for c in 'AB':
     3         yield c
     4     for i in range(3):
     5         yield i
     6 print(list(gen1()))
     7 
     8 以上是将生成器中的数据以列表的方式打印
     9 以下的执行效果与上面相同,运用了yield from 语法
    10 def gen2():
    11     yield from 'AB'
    12     yield from range(3)
    13 
    14 print(list(gen2()))
    View Code

    ⑤生成器函数进阶

    send():

    1. send和next的作用相同
    2. 第一次不能用send
    3. 函数中的最后一个yield不能接受新的值
       1 # 计算移动平均值的例子
       2 def average():
       3     sum = 0
       4     count = 0
       5     avg = 0
       6     while True:
       7         num = yield avg
       8         sum += num
       9         count += 1
      10         avg = sum / count
      11 
      12 avg_g = average()
      13 avg_g.__next__()
      14 
      15 print(avg_g.send(20))
      16 print(avg_g.send(40))
      17 print(avg_g.send(60))
      View Code
       1 # 计算移动平均值的例子
       2 def average():
       3     sum = 0
       4     count = 0
       5     avg = 0
       6     while True:
       7         num = yield avg
       8         sum += num
       9         count += 1
      10         avg = sum / count
      11 
      12 avg_g = average()
      13 avg_g.__next__()
      14 
      15 print(avg_g.send(20))
      16 print(avg_g.send(40))
      17 print(avg_g.send(60))
      View Code

      ⑥生成器表达式

       1 '''
       2 列表推导(列表生成式)
       3 '''
       4 
       5 # 简单的列表推导
       6 l = [i ** 2 for i in range(10)]
       7 print(l)
       8 
       9 '''
      10 生成器表达式
      11 与列表推导相似,返回生成器对象
      12 '''
      13 
      14 g = (i ** 2 for i in range(10))
      15 
      16 # 生成器的第一种调用方式:__next__
      17 print(g.__next__())
      18 
      19 # 生成器的第二种调用方式:for循环
      20 for i in g:
      21     print(i)
      22 
      23 # 生成器的第三种调用方式:类型强转
      24 print(list(g))
      View Code

      ⑦各种推导式

       1 '''
       2 列表推导
       3 [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型]    #遍历之后挨个处理
       4 [满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素相关的条件]   #筛选功能
       5 '''
       6 # 简单的列表推导
       7 l = [i ** 3 for i in range(10)]
       8 print(l)
       9 >>> [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
      10 
      11 # 带筛选的列表推导
      12 l = [i ** 3 for i in range(10) if i % 3 == 0]
      13 print(l)
      14 >>> [0, 27, 216, 729]
      15 
      16 # 多层列表推导
      17 double_l = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
      18             ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
      19 l = [name for lst in double_l for name in lst if name.count('e') >= 2]
      20 print(l)
      21 >>> ['Jefferson', 'Wesley', 'Steven', 'Jennifer']
      22 
      23 '''
      24 字典推导
      25 '''
      26 # 例一:将一个字典的key和value对调
      27 mcase = {'a': 10, 'b': 34}
      28 mcase_frequency = {mcase[k]: k for k in mcase}
      29 print(mcase_frequency)
      30 >>> {34: 'b', 10: 'a'}
      31 
      32 # 例二:合并大小写对应的value值,将k统一成小写
      33 mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
      34 mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
      35 print(mcase_frequency)
      36 >>> {'b': 34, 'a': 17, 'z': 3}
      37 
      38 '''
      39 集合推导
      40 '''
      41 # 计算列表中每个值的平方,自带去重功能
      42 squared = {x ** 2 for x in [1, -1, 2]}
      43 print(squared)
      44 >>> {1, 4}
      45 
      46 '''
      47 练习题
      48 '''
      49 
      50 # 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母
      51 lst = ['123', 'ab', 'y', 'abcabc', 'okiuj']
      52 l = [i.upper() for i in lst if len(i) > 3]
      53 print(l)
      54 >>> ['ABCABC', 'OKIUJ']
      55 
      56 # 答案
      57 # [name.upper() for name in names if len(name)>3]
      58 
      59 # 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元组列表
      60 lst = [(4, 3), (3, 2), (8, 1), (8, 6)]
      61 t = [i for i in lst if ((i[0] % 2 == 0) and (i[1] % 2 != 0))]
      62 print(t)
      63 >>> [(4, 3), (8, 1)]
      64 
      65 # 答案
      66 # [(x,y) for x in range(5) if x%2==0 for y in range(5) if y %2==1]
      67 
      68 # 求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
      69 M = [[1,2,3],[4,5,6],[7,8,9]]
      70 l = [i[2] for i in M]
      71 print(l)
      72 >>> [3, 6, 9]
      73 
      74 # 答案
      75 # [row[2] for row in M]
      View Code

猜你喜欢

转载自www.cnblogs.com/kylindemi/p/12637357.html