浅谈迭代器和生成器

一.迭代器

写在前面 —— 可迭代对象

简单来说,能用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网络爬虫开发实战 ,崔庆才著]

原文地址:https://www.cnblogs.com/lc-snail/p/13274219.html