zoukankan      html  css  js  c++  java
  • 迭代器、生成器

    print(dir([])) #显示列表拥有的所有方法

    1 print(dir([])) #显示列表拥有的所有方法
    2 
    3 
    4 
    5 #结果如下:
    6 ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
    View Code
    可以被for循环的都是可迭代的,要想可迭代,内部必须有一个__iter__方法
    iterable  可迭代的  —> _iter_  只要含有_iter_方法的都是可迭代的
    []._iter_() 迭代器     —>_next_ 通过next就可以从迭代器中一个一个的数值
     
    __iter__方法做了什么事情呢?
    l = [1,2,3,4,5]
    print(l.__iter__())
    
    
    #结果
    <list_iterator object at 0x109896518>

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

    iterator,这里给我们标出来了,是一个计算机中的专属名词,叫做迭代器。

    '''
    dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,
    然后取差集。
    '''
    #print(dir([1,2].__iter__()))
    #print(dir([1,2]))
    print(set(dir([1,2].__iter__()))-set(dir([1,2])))
    
    结果:
    {'__length_hint__', '__next__', '__setstate__'}

    我们看到在列表迭代器中多了三个方法,那么这三个方法都分别什么用途呢?

    iter_l = [1,2,3,4,5,6].__iter__()
    #获取迭代器中元素的长度
    print(iter_l.__length_hint__())
    #根据索引值指定从哪里开始迭代
    print('*',iter_l.__setstate__(4))
    #一个一个的取值
    print('**',iter_l.__next__())
    print('***',iter_l.__next__())

    __next__能让我们一个一个取值

    在for循环中,就是在内部调用了__next__方法才能取到一个一个的值。

    那接下来我们就用迭代器的next方法来写一个不依赖for的遍历。

    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)

    但是这段代码在最后报错了,因为我们一直取next取到迭代器里已经没有元素了,就会抛出一个异常StopIteration,告诉我们,列表中已经没有有效的元素了。

    接下来稍作修改,把这个异常报错处理掉:

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

    现在我们就使用while循环实现了原本for循环做的事情,我们是从l_iter获取一个一个的值,这个l_iter就是一个迭代器。

    只要含有_iter_方法的都是可迭代的   ----可迭代协议
    迭代器协议 ——内部含有_next_和_iter_方法的就是迭代器
    迭代器的好处:
                            从容器类型中一个一个的取值,会把所有的值都取到。
                            节省内存空间
                            迭代器并不会在内存中再占用一大块内存,而是随着循环每次生成一个,
                            每次_next_提供一个
     
     
     
    生成器:
        生成器函数

    Python中提供的生成器:

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

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

     

    生成器Generator:

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

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

    生成器函数

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

    def count():
        yield 1
        yield 2
        yield 3
        yield 4
        yield 5
        yield 6
        yield 7
        yield 8
    
    g = count()
    print(g)
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    
    
    
    #结果:
    <generator object count at 0x10c30ebf8>
    1
    2
    3
    4
    5
    6
    7
    8

    生成器的应用实例:

    def tail(filename):
        f = open(filename,encoding = 'utf-8')
        while True:
            line = f.readline()
            if line.strip():
                yield line.strip()
                
    g = tail('file')
    for i in g:
        if 'python' in i:
            print('***',i)
    监听用户输入内容并过滤出有关python关键字的行

    生成器函数进阶:

    def generator():
        print(123)
        content = yield 1
        print('######',content)
        print(456)
        yield 2
     
     
    g = generator()
    ret = g.__next__()
    print('****',ret)
    ret = g.send('hello’)   #send的效果和next一样
    print('***',ret)
     
    #结果:
    123
    **** 1
    ###### hello
    456
    *** 2
     
    #send 获取下一个值的效果和next基本一致
    #只是在获取下一个值的时候,给上一个值的位置传递一个数据
            #使用注意事项:
                        #第一次使用生成器的时候,必须用next获取下一个值
                        #最后一个yield不能接受外部的值
     
    实例:获取移动平均值
     
    def average():
        sum = 0
        count = 0
        avg = 0
        while 1:
            num = yield avg
            sum += num
            count += 1
            avg = sum/count
     
    avg_g = average()
    avg_g.__next__()
    avg1 = avg_g.send(10)
    print(avg1)
    avg1 = avg_g.send(20)
    print(avg1)
    avg1 = avg_g.send(30)
    print(avg1)
     
    结果:
    10.0
    15.0
    20.0
     
     
    #列表推导式
    list = [i for i in range(10)]
    print(list)   #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    #生成器表达式
    g = (i for i in range(10))
    print(g)      #<generator object <genexpr> at 0x100e97d00>  g是一个生成器
    #两者区别:
        #括号不一样
        #返回的值不一样  === 几乎不占用内存
     
    g1 = (i*i for i in range(10))
    for i in g1:
        print(i)
    #[每一个元素或者是和元素相关的操作  for 元素 in 可迭代数据类型]  #遍历之后挨个处理
    #【满足条件的元素相关的操作 for 元素 in 可迭代数据类型  if 元素相关的条件】 #筛选功能
     
    #30以内所有能被3整出的数
     
    ret = [i for i in range(30) if i%3 == 0]
    print(ret)
  • 相关阅读:
    Django高级编程之自定义Field实现多语言
    Python魔法方法__getattr__和__getattribute__详解
    Python深入浅出property特性属性
    Python中使用__new__实现单例模式并解析
    Python中类方法、__new__方法和__init__方法解析
    Python中可迭代对象、迭代器以及iter()函数的两个用法详解
    Docker ubuntu apt-get更换国内源解决Dockerfile构建速度过慢
    Python抽象基类中__subclasshook__方法的使用并实现自己的虚拟子类
    Scrapy-redis分布式爬虫爬取豆瓣电影详情页
    PHP5.5+ APC 安装
  • 原文地址:https://www.cnblogs.com/shi-guang/p/8178787.html
Copyright © 2011-2022 走看看