文章目录
- 一、可迭代
- 1. 可迭代的判定
- 2. Iterable 可迭代的定义
- 二、Iterators 迭代器
- A. 定义
- B. 生成迭代器iterators.__iter__()
- C. 迭代协议
- D. 为什么要用迭代器
- E. 怎样制造迭代器******
- 总结
一、可迭代
1. 可迭代的判定
# 验证是否是迭代器或可迭代
from collections.abc import Iterable,Iterator
>>> isinstance(list(),Iterable)
True
>>> isinstance(list(),Iterator)
False
>>>
2. Iterable 可迭代的定义
可用for loop实现访问,或者是类中包含iter(),则称为可迭代。
# 自定义 iterable
from collections.abc import Iterable
class count1:
def __init__(self, start=0):
self.num=start
def __iter__(self):
return self
obj = count1(1)
print(isinstance(obj, Iterable)) # True
- 常见的list,tuple,dict,set,str
- 使用iter()后生成迭代器,也可以用next()访问
- 可迭代包含迭代器:即Iterable包含Iterators
二、Iterators 迭代器
A. 定义
- 迭代中可以记忆自己的状态
- 有__next__方法
- 自动跳到下一个值
- 在下一个值时更新状态
- 结束时信号会raise StopIteration异常
- 可用try…except来处理
itr = iter([1,2,3])
print(next(itr))
print(next(itr))
print(next(itr))
# print(next(itr)) # StopIteration
可迭代的,且有__iter__方法,即迭代器
B. 生成迭代器iterators.iter()
- 如果可迭代的话,则获得迭代器
- 如果不可迭代的话,则通过索引生成迭代器
- 若均不满足,就raise TypeError
- 可用try…except来处理
C. 迭代协议
- __iter__()
- __next__() 调用next()可以不断指向下一个值
- 所有可迭代的都可以用**内置函数 iter()**获得迭代器,之后可以使用next()
- 常见的list,tuple,dict,set,str,均是Iterator的子类
- open读取后,可以用next调用
D. 为什么要用迭代器
- lazy:不用考虑下一个是什么,自动next
- 有时节省时间和内存,相对list等数据结构(见例题)
- 可以生成无穷长的迭代器,且占用内存很小
E. 怎样制造迭代器******
- 对象导向的生成器
可以自建一个class ,包含__init__ \ iter\ next(见例子)
# 自定义 iterator
class count1:
def __init__(self, start=0):
self.num=start
def __iter__(self): # 记录自己的状态
return self
def __next__(self): # 返回到下一个值
self.num += 1
return self.num
- 生成器函数
自建一个def,包含yield语句,收集元素,并返回一个generator对象,即迭代器。
其中,yield语句可以是一个或多个,通过for循环,按顺序收集迭代值(见例子)
def count2(start=0):
num = start
while True:
yield num
num += 1
- 注:
- 当called时,会返回迭代器但不会立即运行。
- 可以做一个无穷的迭代器函数,要比对象导向的更简洁
- 生成器的表达式
自建一个类似list的表达式 (x for x in L).
L = list(range(1,11))
cubes = (x**3 for x in L)
- 注:
- 类似于for loop加append
- 比生成函数更简洁
总结
- 迭代器和可迭代的不同点是,迭代中是有属性next+iter,而可迭代中有iter或getitem
- 不同生成器的简洁性:表达式 > 函数 > 表达式
- return 和yield的比较
- return
函数的终点、返回值或者None、摧毁了所有的局部变量 - yield
暂停函数的执行、获取值不摧毁局部变量、之后会从停下来的地方接着运行