zoukankan      html  css  js  c++  java
  • 浅谈迭代器和生成器

    一.迭代器

    写在前面 —— 可迭代对象

    简单来说,能用for循环遍历的对象,都能称为可迭代对象,比如,列表(list), 集合(set),元组(tuple)等,可以使用for循环迭代的标志是内部实现了iter方法。

    1.概念

    简单来说迭代器是可以实现迭代过程的容器。可迭代对象一般只能按默认的正序方式进行迭代,你可以通过为其添加next()函数来定制不同的迭代方式,这样通过next()函数封装起来的迭代对象生成器就被称作迭代器。

    2.创建

    字符串,列表,集合都可以用于创建迭代器。

    list = [1,2,3,4]
    it = iter(list)
    print(it) #输出<list_iterator object at 0x00000181562C0850>
    print(next(it) #输出 1
    print(next(it) #输出 2
    '''
    iter()函数是创造一个迭代器对象
    next()函数是迭代出下一个元素
    '''
    

    创建一个迭代器

    把一个类作为一个迭代器使用需要在类中实现两个方法 iter() 与 next() 。

    class MyNumbers:
      def __iter__(self):
        self.a = 1
        return self
     
      def __next__(self):
        if self.a <= 5:
          x = self.a
          self.a += 1
          return x
        else:
          raise StopIteration 
     
    myclass = MyNumbers()
    myiter = iter(myclass)
     
    for x in myiter:
      print(x,end=" ")  #输出 1 2 3 4 5 
    

    要看迭代器生成器详解的道友移步这位大佬的博客

    二.生成器

    1.概念

    在python中我们经常用列表来存储数据,但是受到内存容量的限制,列表的容量是有限制的,而且我们生成一个包含很多元素的列表,不仅会占用很多内存,如果我们只是需要列表中其中一小部分元素,那么剩下的元素占用的内存空间就会白白浪费。

    所以,我们可以根据需要写算法推算出列表元素,在循环的过程中不断推算出后续元素,这样就不需创建完整list,从而节省大量的空间。在python中,这种一边循环一边计算的机制,称为生成器:generator。

    1.创建

    (1)方法1

    把列表生成式中的中括号 [ ] 换成小括号 ( ) ,就创建了一个生成器。

    demo

    #创建列表
    L = [x*x for x in range(10)]
    print(L)  #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    print(type(L)) #<class 'list'>
    #创建生成器
    g = (x*x for x in range(10))
    print(g)  ##<generator object <genexpr> at 0x000002657D5A32E0>
    print(type(g)) #<class 'generator'>
    

    (2)方法2

    利用关键字yield来创建生成器。

    demo1 —— 普通实现斐波那契数列函数

    def fb(max):
        n,a,b=0,0,1
        while n < max:
            print(b,end='==')
            a,b = b,a+b
            n+=1
    
    fb(10) #输出1==1==2==3==5==8==13==21==34==55==
    
    '''
    a,b=a,a+b相当于
    t = (b, a + b) # t是一个tuple
    a = t[0]
    b = t[1]
    '''
    

    demo2 —— 实现斐波那契数列生成器

    def fb(max):
        n,a,b=0,0,1
        while n < max:
            yield b
            a,b = b,a+b
            n+=1
    
    print (fb(10)) #
    for i in fb(10):
        print(i,end="==")  #输出1==1==2==3==5==8==13==21==34==55==
    

    带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator。调用 fb(10)的时候不会执行 fb 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fb 函数内部的代码,执行到 yield b 时,fb 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

    参考廖雪峰官网

    参考菜鸟教程

    实战运用

    展开
    import  requests
    import re
    import time
    
    def get_one_page(url):
        try:
            headers = {
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36 Edg/83.0.478.56"
                }
            r=requests.get(url,headers=headers)
            if r.status_code==200:
                print('ok')
                return r.text
        except RequestException:
            return None 
    
    
    #获取排名,图片,电影名称,主演,发布时间,评分
    def parse_one_page(html):
       
        pattern = re.compile('<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)'
        +'</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>'
        +'(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>',re.S)
       
        items = re.findall(pattern,html)
        
        for item in items:
            yield {
                  '排名':item[0],
                  '图片':item[1],
                  '电影名':item[2],
                  '主演':item[3].strip(),
                  '上映时间':item[4].strip(),
                  '评分':item[5]+item[6]
            }
    def main(offset):
        url = 'http://maoyan.com/board/4?offset=' + str(offset)
        html = get_one_page(url)
        for item in parse_one_page(html):
            print(item)
    if __name__ == "__main__":
        for i in range(10):
            main(offset=i*10)
            time.sleep(2)
    

    参考 [Python 3网络爬虫开发实战 ,崔庆才著]

  • 相关阅读:
    利用pyinotify监控文件内容,像tailf命令但比它更强
    AWS SDK for C++调用第三方S3 API
    Windows 10恢复Shift+右键打开命令提示符窗口
    TP-LINK WR841N V8刷OpenWRT
    Build subversion 1.8 with SSL on OS X Yosemite
    OpenWrt自定义和官方一样的固件
    Windows 10下通过蓝牙连接iPhone个人热点进行共享上网
    Broadcom有线网卡在Windows 8/8.1/10下使用系统自带驱动会断网的解决办法
    BCM94352HMB蓝牙BCM20702A0在Ubuntu 14.04下的驱动方法
    Spring Boot 发送邮件
  • 原文地址:https://www.cnblogs.com/lc-snail/p/13274219.html
Copyright © 2011-2022 走看看