• 迭代器和生成器


    迭代的概念:迭代就是可以被遍历的数据类型,也就是可以被一个一个取出来。

    那么可迭代的类型有哪些?

    from collections import Iterable
                                 
    l = [1,2,3,4]                
    t = (1,2,3,4)                
    d = {1:2,3:4}                
    s = {1,2,3,4}                
                                 
    print(isinstance(l,Iterable))
    print(isinstance(t,Iterable))
    print(isinstance(d,Iterable))
    print(isinstance(s,Iterable))
    View Code

    这里可以看出,元组,列表,字典,集合,包括字符串都是可迭代的。

    1)为什么可以被迭代呢?

    这就要说一下迭代的协议。

    迭代的协议就是内部含有——lter——方法。

    2)什么是迭代器?

    print([1,2].__iter__())
    
    结果
    <list_iterator object at 0x1024784a8>
    View Code

    执行了list([1,2])的__iter__方法,我们好像得到了一个list_iterator,现在我们又得到了一个新名词

    ——iterator。

    iterator的意思就是迭代器。

    迭代器和可迭代的对面之间的区别就是在内容里面多了一个:__next__,这也是他们之间的最根本区别。

    __next__:迭代器就是因为多了这个才可以一个个迭代(遍历),

    l = [1,2,3,4]
    l_iter = l.__iter__()
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    item = l_iter.__next__()
    print(item)
    View Code

    上路的可迭代对象如果遍历完,那么就会报错。有时候我们就有一些异常的办法把异常处理出去:

    l = [1,2,3,4]
    l_iter = l.__iter__()
    while True:
        try:
            item = l_iter.__next__()
            print(item)
        except StopIteration:
            break
    View Code

    标准格式就是list.__next__(),这之前要看他是不是可迭代对象,如果不行就用__iter__()把他变成可迭代对象,然后在用next一个个遍历.

    迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。

    3)range()是迭代器吗?

    from collections import  Iterator
    print(isinstance(range(100000000),Iterator))  
    print(isinstance(range(100),Iterator))
    这里的isinstance是查看里面的值是什么数据类型,Iterator就是看看是不是迭代器。

    4)迭代器有什么作用:最重要的一点就是可以节省内存空间。

    Python中提供的生成器:

    1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

    2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

    生成器Generator:

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

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

    import time
    def genrator_fun1():
        a = 1
        print('现在定义了a变量')
        yield a
        b = 2
        print('现在又定义了b变量')
        yield b
    
    g1 = genrator_fun1()
    print('g1 : ',g1)       #打印g1可以发现g1就是一个生成器
    print('-'*20)   #我是华丽的分割线
    print(next(g1))
    time.sleep(1)   #sleep一秒看清执行过程
    print(next(g1))
    
    初识生成器函数
    View Code
    这里有一些注意:首先运行一次genrator_fun1()的话,只会显示他是一个生成器,不会显示别东西,只有当你调用next(genrator_fun1())的话,他才会运行,但是你掉一次next他就只会运行到第一个yield,就不会再运行,只有你一下子调用2个next的时候,他才会一下子运行2个,并且把值返回到genrator_fun 里,下面谁接收的话,就给谁,另外,每一次调用后,当你重新调用的时候,程序又会重新从第一个开始运行。
    ps:如果yield后面带了东西,当你运行到那的时候才会取出来。

    下面是一些例子:

    import tima
    def func():
        f=open(filename)
        f.seak(0,2)
        while True:
            line=f.readline()
            if not line:
                time.sleep(0.2)
                continue
            else:
                yield  line
    l=func()
    for line in l:
        print(line)
    View Code
    #初识生成器二
    
    def produce():
        """生产衣服"""
        for i in range(2000000):
            yield "生产了第%s件衣服"%i
    
    product_g = produce()
    print(product_g.__next__()) #要一件衣服
    print(product_g.__next__()) #再要一件衣服
    print(product_g.__next__()) #再要一件衣服
    num = 0
    for i in product_g:         #要一批衣服,比如5件
        print(i)
        num +=1
        if num == 5:
            break
    
    #到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
    #剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
    View Code
    #初识生成器二
    
    def produce():
        """生产衣服"""
        for i in range(2000000):
            yield "生产了第%s件衣服"%i
    
    product_g = produce()
    print(product_g.__next__()) #要一件衣服
    print(product_g.__next__()) #再要一件衣服
    print(product_g.__next__()) #再要一件衣服
    num = 0
    for i in product_g:         #要一批衣服,比如5件
        print(i)
        num +=1
        if num == 5:
            break
    
    #到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
    #剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
    衣服生产
    def averager():
        total = 0.0
        count = 0
        average = None
        while True:
            term = yield average
            total += term
            count += 1
            average = total/count
    
    
    g_avg = averager()
    next(g_avg)
    print(g_avg.send(10))
    print(g_avg.send(30))
    print(g_avg.send(5))
    
    计算移动平均值(1)
    平均值的计算
    def init(func):  #在调用被装饰生成器函数的时候首先用next激活生成器
        def inner(*args,**kwargs):
            g = func(*args,**kwargs)
            next(g)
            return g
        return inner
    
    @init
    def averager():
        total = 0.0
        count = 0
        average = None
        while True:
            term = yield average
            total += term
            count += 1
            average = total/count
    
    
    g_avg = averager()
    # next(g_avg)   在装饰器中执行了next方法
    print(g_avg.send(10))
    print(g_avg.send(30))
    print(g_avg.send(5))
    平均值带装饰器

    下面是一个生成器yield   from 的一些应用

    def gen1():
        for c in 'AB':
            yield c
        for i in range(3):
            yield i
    
    print(list(gen1()))
    
    def gen2():
        yield from 'AB'
        yield from range(3)
    
    print(list(gen2()))
    yield from

    列表表达式和生成器表达式:

    之间的差别:列表表达式占系统内存空间较多,生成器几乎不占内存。

    list=[x  for x in range(10000) ]---列表表达式

    list=(x  for x in range(10000))---生成器表达式

  • 相关阅读:
    中断子系统5_电流层处理
    太极拳透劲的原理推测
    OpenSSL命令---pkcs7
    初步分析美国科研项目申报项目
    OpenSSL命令---pkcs8
    C#中Hashtable的用法
    android 中 ViewPager 的平常用法 ViewPager+ Views
    打卡汇报
    OpenSSL命令---pkcs12
    卡卡游戏引擎之快速入门
  • 原文地址:https://www.cnblogs.com/52forjie/p/7276939.html
Copyright © 2020-2023  润新知