文章目录
一、可迭代对象
可以进行迭代操作的一对象,也可以解释为可以用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
继续执行
这里有必要分析下这个程序的执行流程:
-
首先,在创建有 num 生成器的前提下,通过其调用 next() 内置函数,会使 Python 解释器开始执行 intNum() 生成器函数中的代码,因此会输出“开始执行”,程序会一直执行到yield i,而此时的 i==0,因此 Python 解释器输出“0”。由于受到 yield 的影响,程序会在此处暂停。
-
然后,我们使用 num 生成器调用 next() 方法,该方法的作用和 next() 函数完全相同(事实上,next() 函数的底层执行的也是 next() 方法),它会是程序继续执行,即输出“继续执行”,程序又会执行到yield i,此时 i==1,因此输出“1”,然后程序暂停。
-
最后,我们使用 for 循环遍历 num 生成器,之所以能这么做,是因为 for 循环底层会不断地调用 next() 函数,使暂停的程序继续执行,因此会输出后续的结果