什么是迭代器
在 Python 中,迭代器(Iterator)是一个访问集合元素的对象,它能够实现遍历集合的所有元素,而无需了解集合底层结构和细节。Python 中所有可迭代的对象(如 列表、元组、字符串、字典、集合等)都可以通过内置函数 iter() 获取对应的迭代器,然后使用内置函数 next() 逐个获取元素。当集合中的所有元素被遍历完成后,再次使用 next() 函数会抛出 StopIteration 异常。
什么是可迭代对象
在 Python 中,可迭代对象(Iterable)是指可以被迭代的对象,也就是包含多个元素并且支持使用 for 循环语句进行遍历的对象。Python 中许多内置的数据类型都属于可迭代对象,包括列表、元组、字符串、字典、集合等。
我们可以使用isinstance()方法和collections.abc中的Iterable类型来检查一个东西是否为可迭代对象。
例:
from collections.abc import Iterable
a = {1:"1",2:[1,2,3]}
print(isinstance(a,Iterable))
True
返回值为True
python内置类型中自带的迭代器
python中有很多内置类型就是可迭代对象,可迭代对象就说明这个东西可以通过iter()方法变为迭代器,举一个列表的例子。
a = [1,2,3]
a这个列表就是一个可迭代对象,我们先通过instance()方法检查这个列表是否为可迭代对象。
print(isinstance(a,Iterable))
True
for i in a:
print(i)
这里其实就用到了可迭代对象的特性
注意:python在进行for 语句遍历循环的时候,会隐式的把需要遍历的对象转换成迭代器,并不断调用迭代器中的__next__()魔法函数,把迭代器中的对象一个一个的返回出来。
自定义可迭代器
class Iterable(object):
def __init__(self):
pass
def __iter__(self):
return self
def __next__(self):
pass
if __name__ == '__main__':
i = Iterable()
这个是自定义迭代器的一个基本模板,除了初始化方法__init__()之外还有__iter__、next__两个魔法方法,这两个方法前者负责返回自身,所以它的返回值必须是self,而__next()方法负责迭代器主要的业务逻辑,需要根据不同的情况编写。
这里举一个经典的斐波那契额数列的例子:
class Fib:
def __init__(self):
self.prev,self.cur = 0,1
def __iter__(self):
return self
def __next__(self):
self.cur,self.prev = self.cur + self.prev,self.cur
return self.cur
def fib():
cur,prev = 1,0
while 1:
yield cur
cur,prev = cur + prev,prev
if __name__ == '__main__':
fib = Fib()
for i in range(10):
print(next(fib))
这段代码中的带yield的fib()函数是生成器函数
什么是生成器
生成器(Generator)是一种特殊的迭代器,它使用 yield 语句来产生值。与普通的迭代器相比,生成器更加简洁、高效,能够在遍历元素的同时动态生成新的元素,而不会像列表解析那样一次性占用大量内存空间。
def my_generator():
yield 1
yield 2
yield 3
yield 4
for item in my_generator():
print(item) # 依次输出 1, 2, 3, 4
控制台会依次输出 1, 2, 3, 4
构建生成器的两种方式
上述代码是构建生成器的两种方式之一,也就是用函数来构建。
- 生成器函数
函数用yield返回值,这种函数叫生成器函数。函数被调用时会返回一个生成器对象。
def my_generator():
yield 1
yield 2
yield 3
yield 4
# for item in my_generator():
# print(item) # 依次输出 1, 2, 3, 4
print(my_generator())
<generator object my_generator at 0x0000018F46583C10>
当打印这个执行函数时,控制台会返回这个信息,这个信息说明该函数返回的是一个generator (也就是生成器)对象。
生成器对象可以在当他被遍历的时候,自动调用__iter__()方法和__next__()方法,而且生成器是用一种懒加载的模式生成值,所以不需要担心生成器生成的值会一次性写入内存中,它会一个一个的写入内存。
- 生成器表达式
g = (i for i in range(5))
用类似这样的表达式就能生成一个生成器,现在g就是一个迭代器,同时也是生成器。
from collections.abc import Iterable
g = (i for i in range(5))
print(isinstance(g,Iterable)) # 返回值为True
print(iter(g)) # <generator object <genexpr> at 0x00000125451E3C10>
注意:生成器也可以是一个可迭代对象,因此我们可以遍历它:
for i in g:
print(i)
yield与return的区别
- 包含 return 的方法会以 return 关键字为最终返回,每次执行都返回相同的结果
- 而包含yield方法的生成器每次执行时遇到 yield 就返回 yield 后的结果,但内部会保留上次执行的状态,下次继续迭代时,会继续执行 yield 之后的代码,直到再次遇到 yield 后返回