第二篇
先给出生成器与迭代器的例子,然后详细讲解需要理解的知识。
# 生成器
a = (i+1 for i in range(10))
# 列表推导式,不是生成器
b = [i+1 for i in range(10)]
# 生成器
def generator(n):
z = 1
while z<n:
z += 1
yield z
return "done"
c = generator(5)
# 如果不信可以使用print验证
print(a,b,c,sep="\n")
输出结果
at 0x000001D1B1E48570>
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 迭代器
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1
# 返回迭代器对象本身
def __iter__(self):
return self
# 返回容器下一个元素
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
d = Fib()
# 判断d是否为迭代器
isinstance(d, Iterator)
输出结果
True
在 Python 中,迭代器是指遵循迭代器协议(iterator protocol)的对象。
迭代器协议:任意对象只要定义了__iter__
方法和__next__
方法就是迭代器,就像上面例子给出的一样。
再说明一下与迭代器相关的名词:迭代与可迭代对象
迭代(Iteration):当我们用一个循环(比如 for 循环)来遍历容器(比如列表,元组)中的元素时,这种遍历的过程就叫迭代。
可迭代对象(Iterable):直观上可以用for循环遍历的对象就是可迭代对象。 严格地定义说,Python中任意的对象,只要它定义了可以返回⼀个迭代器的__iter__
⽅法,或者定义了可以⽀持下标索引的__getitem__
⽅法,那么它就是⼀个可迭代对象。
相同点:都可以使用for循环取出元素。
不同点:迭代器一定是可迭代对象,但可迭代对象不一定是迭代器。迭代器可以使用python内置的next方法一个一个取出元素,而可迭代对象不行。(从上面的定义也可以看出,因为可迭代对象没有实现__next__
方法)
iterator = (i+1 for i in range(5)) # 迭代器
iterable = [i+1 for i in range(5)] # 可迭代对象
# 判断itrable为可迭代对象
from collections import Iterable
isinstance(iterator, Iterable) # True
isinstance(iterable, Iterable) # True
hasattr(iterable,'__iter__') # True
hasattr(iterable,'__getitem__' # True
# 判断iterator是否为迭代器
from collections import Iterator
isinstance(iterator, Iterator) # True
isinstance(iterable, Iterator) # False
# iterator可以使用next方法
next(iterator) # 1
# iterable不能使用next方法
next(iterable) # 'list' object is not an iterator
与列表不同,迭代器不会把元素一次性加载到内存,而是以延迟方式加载。如列表中含有一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素。这样就不会消耗大量资源。(在使用for循环迭代的过程中,本质上是调用迭代器的next方法取出元素)
生成器(generator)也是一种迭代器,它有和迭代器一样的特性,唯一的区别在于生成器的构造方式更加简洁。它通常采用yield
将函数构造生成器或者使用生成器表达式()
构造生成器。具体如何构造可以参考1.1 生成器
的例子
极客学院——生成器
极客学院——迭代器
生成器与迭代器