Python迭代器与生成器
列表生成式
列表生成式也叫做列表推导式,它本身还是列表,只不过它是根据我们定义的规则来生成一个真实的列表。
list2 = [x for x in range(10)]
print(list2)
下面是一个复杂的列子:
list1 = [x * y for x in range(1, 5) if x > 2 for y in range(1, 4) if y < 3]
# 上面的列表生成式等同于下面的代码
list4 = []
for x in range(1, 5):
if x > 2:
for y in range(1, 4):
if y < 3:
list4.append(x * y)
生成器
如果要创建一个100万个元素的列表,你使用上面的方式无疑非常占用内存,这时候就用到了生成器,它其实是保存一个你定义的规则,在需要用到元素的时候按照规则去生成一个,而不是保存好一大堆元素,这样就减少内存占用。不过生成器的元素只能顺序依次获取不能像真正列表那样可以按位置获取而且不能回退。
创建一个生成器,生成器保存的是一个算法,而不是具体的内容。可以看到和列表生成式的区别是就是把[]换成(),generator = (x for x in range(10))
。
其实生成器就是一个迭代器,只不过它是一种特殊的迭代器:
print("generator是否是迭代器:", isinstance(generator, Iterator)) # 结果为 True
print("generator是否是可迭代对象:", isinstance(generator, Iterable)) # 结果为 True
如果要想获取生成器元素就只能通过next来获取下一个元素,必须顺序获取,当没有元素的时候抛出 StopIteration 异常。print(generator.__next__()) # 也可以这样来使用 next(generator)
。
用生成器实现斐波那契数列:
def fib(length):
"""
生成器定义一个斐波那契数列,生成器本身就是yield + next实现。外部调用next来触发一次计算
函数遇到yield返回,然后下一次next则继续从上一次yield的地方向下执行,直到遇到某个结束条件
:param length:
:return:
"""
n, a, b = 0, 0, 1
while n < length:
yield b
"""
a, b = b, a + b 等于 t = (b, a + b) a=t[0] b=t[1] 当计算b = a + b的时候,
这里的a并不是之前 a = b 之后a值,而是之前的a值,所以它是先做 = 右边的计算,然后赋值给左边的
"""
a, b = b, a + b
n = n + 1
return 'done'
for i in fib(10):
print(i)
迭代器
可以用next()函数调用来获取下一个元素的对象叫做迭代器。生成器就可以,但是普通集合类比如list、dict、str就不可以。集合类的对象比如list、dict、set、str;还有生成器都是可迭代对象,也就是可以遍历的。但是它们并不一定都是迭代器。list、dict、str等数据类型不是Iterator。
list1 = [1, 2, 3, 4, 5, 6]
print("list1是否是迭代器:", isinstance(list1, Iterator)) # 结果为 False
print("list1是否是可迭代对象:", isinstance(list1, Iterable)) # 结果为 True
print("list1的长度:", len(list1)) # 结果为具体长度
if hasattr(list1, "__next__"):
print("list1是迭代器")
把list1变成迭代器:
interObj = iter(list1)
print("list1是否是迭代器:", isinstance(interObj, Iterator)) # 结果为 True
print("list1是否是可迭代对象:", isinstance(interObj, Iterable)) # 结果为 False
# print("interObj的长度:", len(interObj)) # 无法获取长度
if hasattr(interObj, "__next__"):
print("interObj是迭代器")
- 可遍历的对象不一定是迭代器,但是肯定是可迭代对象。
- 迭代器同时一定也是可迭代对象。生成器是一种特殊的迭代器,所以也是可迭代对象。
- 可迭代对象和迭代器最大的区别就是前者可以通过len()获取长度而后者不能
- 且迭代器一定可以通过next()函数(说明该对象包含__next__内置方法)获取下一个元素,而可迭代对象不一定。