深入理解迭代器和生成器
古之立大事者,不唯有超世之才,亦必有坚韧不拔之志 – 苏轼
迭代
迭代指得是通过重复执行某个操作,不断获取被迭代对象中得数据.每一次操作就是一次迭代
迭代是遍历得一种形式.例如我们之前学的 For 循环, 它能不断得从列表,元祖,字符串,集合,字典等容器中取出新元素,每次一个元素直至所有元素被取完.这种 for 循环就是迭代
for item in [1,2,3,4,5]:
print(item)
# 结果 1,2,3,4,5
迭代器
迭代器得使用方法
# 迭代器 = iter(容器)
numbers = [1,2,3,4,5]
iterator = iter(numbers)
# 上面得iterator就是一个迭代器
这个迭代器用于迭代列表中的所有元素.
要使用迭代器只需要迭代器调用内置函数 next(),便可逐一获取其中所有的值
# 值 = next(迭代器)
arr = [1, 2, 3, 4, 5]
iterator = iter(arr)
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
# 结果
# 1
# 2
# 3
# 4
# 5
可以看到每次调用 next()将一次返回列表中的一个值.直到所有的值被遍历一遍,此时抛出异常代表迭代终止
for 循环的迭代过程
for 循环的迭代就是通过使用迭代器来完成:
对一个容器调用 iter()函数获取该容器的迭代器
每次循环时对迭代器调用 next()函数,以获取一个值
若捕获到异常则结束循环
什么是可迭代的
从表面上看所有可用于 for 循环的对象都是可迭代的,如列表,元祖,字符串,集合,字典等容器
从深层看 定义了__iter__()方法的类对象就是可迭代的.当这个类对象被 iter()函数使用时,将返回一个迭代器对象.如果对象有__iter__()方法,则可以说它支持迭代协议
判断一个已有的对象是否可迭代
- 通过内置函数 dir()获取这个对象的所有方法,检查是否有 ‘__iter__‘
'__iter__' in dir(list)
# True
'__iter__' in dir(int)
# False
- 使用内置函数 isinstance()判断其是否为 iterable 的对象
from collections.abc import Iterable
isinstance([1,2,3],iterable)
自定义迭代器
我们可以自己来定义迭代器类,只要在类种定义__next__()和__iter__()方法即可
- 基本语法
class MyIterator:
def __next__(self):
代码块
def __iter__(self):
return self
- 实例化
class PowerOfTwo:
def __init__(self):
self.exponent = 0 # 将每次的指数记录下来
def __next__(self):
if self.exponent>10:
raise StopIteration
else:
result = 2 ** self.exponent
self.exponent +=1
return result
def __iter__(self):
return self
每次对迭代器使用内置函数 next()时,next()将在背后调用迭代器__next__()方法.所以迭代器的重点是__next__()方法的实现,在这个 next 方法中,我们将求职时的指数记录在对象 self.exponenth 中,求值结束时指数加 1,为下次求值做准备
对于方法__iter__()的实现,我们直接返回迭代器对象自身即可。可直接用于 for 循环
扩展 如果对象具有__iter__()和__next__()方法,则可以说它支持携带其协议
- 实例化使用
class PowerOfTwo:
def __init__(self):
self.exponent = 0 # 将每次的指数记录下来
def __iter__(self):
return self
def __next__(self):
if self.exponent > 10:
raise StopIteration
else:
result = 2 ** self.exponent
self.exponent += 1
return result
p = PowerOfTwo()
print(next(p))
print(next(p))
# 结果
# 1
# 2
迭代器的好处
当我们需要逐一获取数据集合中的数据的时候,可以使用迭代器
另外一方面,数据的存储时需要占用内存的。数据越大占用的内存越多.而迭代器可以不保存数据,他的数据可以在需要的时候被计算出来(节省资源)