python高级知识之迭代器和生成器

一、可迭代对象

可以进行迭代操作的一对象,也可以解释为可以用for循环遍历的对象,常见的list tuple set dict str 等都是可迭代对象

# 判断list是否是可迭代对象
# 第一种方法:hasattr
>>> print(hasattr(list,'__iter__'))  
True
# 第二种方法:isinstance(obj,Iterable)
>>> from typing import Iterator 
>>> print(isinstance([1,2],Iterable))
True

二、迭代器(Iterator)

1、协议

1)迭代器类型必须实现__iter__和__next__属性;
2)__iter__必须返回self;
3)__next__必须返回下一个值,如果没有就会抛stopiterator异常;
4)对迭代器操作时自动执行next;
5)只能迭代一次;
6)for语句会忽略StopIteration异常

2、判断是否是迭代器

# 第一种方法:看对象有无__iter__属性和__next__属性,list不是迭代器
>>> print(hasattr(list,'__iter__'))  
True
>>> print(hasattr(list,'__next__'))  
False
# 第二种方法:isinstance(obj,Iterable)
>>> from typing import Iterator
>>> print(isinstance([1,2],Iterable))
False

3、创建迭代器对象

# 用内置函数iter可创建迭代器对象
l1=[1,2,3,4]
it = iter(l1)
# 验证
>>> print(isinstance(it,Iterable))
True

4、自制迭代器

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

from typing import Iterable
class TestIterable:
    def __init__(self):
        self.lists = [1, 2, 3]
        self.index = -1
    def __iter__(self):
        return self
    def __next__(self):
        self.index +=1
        if self.index < len(self.lists):
            return self.lists[self.index]
        else:
            # StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况
            raise StopIteration
if __name__ == '__main__':
    s = TestIterable()
    print(isinstance(s, Iterable))
    for i in s:
        print(i)
---------输出结果------------
True
1
2
3

5、应用场景

1)list保存1-10000个整数会占10000个整数的内存,而迭代器只占用几个整数的内存;
2)爬虫时如果将所有图片保存至列表中会占用大量的内存,而用迭代器代替,每次获得一个图片就保存然后再获取下一个图片,大大降低内存的占用;

三、生成器(generator)

顾名思义,就是生成迭代器的过程,实际内部主要使用了 yield 的函数;

1、yield关键字:

yield关键字:如果函数中包含yield,调用函数时不会执行函数的内容,而是返回一个对象(这个对象是生成器类)。

当要访问生成器的__next__方法时,函数会变成running状态,当执行完yield时,函数变成挂起状态,只有再次执行__next__时才会被唤醒。

什么情况下会执行生成器对象的__next__方法呢? ---------获取生成器下一个值的时候。

2、yield与return区别

1)都是python关键字;
2)return是结束函数的返回值,而yield是暂时离开函数;

3、自制生成器

1)构建生成器

def next2():
	print("开始执行")
    for i in range(5):
        yield i*i
        print("继续执行")
obj2=next2()
    
# s=(i*i for i in range(5))  # 上述生成器的简单写法

2)执行生成器

要想使生成器函数得以执行,或者想使执行完 yield 语句立即暂停的程序得以继续执行,有以下 2 种方式:

  • 通过生成器(上面程序中的 num)调用 next() 内置函数或者 next() 方法;
  • 通过 for 循环遍历生成器

例如,在上面程序的基础上,添加如下语句:

#调用 next() 内置函数
print(next(num))
#调用 __next__() 方法
print(num.__next__())
#通过for循环遍历生成器
for i in num:
    print(i)

程序执行结果为:

开始执行
0
继续执行
1
继续执行
2
继续执行
3
继续执行
4
继续执行

这里有必要分析下这个程序的执行流程:

  1. 首先,在创建有 num 生成器的前提下,通过其调用 next() 内置函数,会使 Python 解释器开始执行 intNum() 生成器函数中的代码,因此会输出“开始执行”,程序会一直执行到yield i,而此时的 i==0,因此 Python 解释器输出“0”。由于受到 yield 的影响,程序会在此处暂停。

  2. 然后,我们使用 num 生成器调用 next() 方法,该方法的作用和 next() 函数完全相同(事实上,next() 函数的底层执行的也是 next() 方法),它会是程序继续执行,即输出“继续执行”,程序又会执行到yield i,此时 i==1,因此输出“1”,然后程序暂停。

  3. 最后,我们使用 for 循环遍历 num 生成器,之所以能这么做,是因为 for 循环底层会不断地调用 next() 函数,使暂停的程序继续执行,因此会输出后续的结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

克里斯蒂亚诺·罗纳尔达

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值