可迭代对象 -> 可迭代对象可以迭代但不是迭代器
list, dic, str, set, tuple, f = open()(文件句柄), range(), enumerate
可迭代的不一定是迭代器,但迭代器一定是可迭代的,因为迭代器中一定有 __iter__ 方法
1. 可迭代: Iterable(可循环)
可迭代协议:只要含有__iter__方法都是可迭代
- dir() -> 查看对象所拥有的方法 -> 判断是否为可迭代的 -> 常用方法
iterable_fn = dir([])
print('__iter__' in iterable_fn) # True
- isinstance() -> 判断一个对象是不是某个东西 -> 判断是否为可迭代的
from collections import Iterable
from collections import Iterator
print(isinstance([], Iterable)) # True
print(isinstance([], Iterator)) # False
2. 迭代器: Iterator -> 迭代器可以被 for 循环
迭代器的好处:
- 从容器类型中一个一个的取值,会把所有的值都取到,而且所有数据只能取一次,取完就没有。(一定要记住该原则)
- 节省内存空间 -> 迭代器并不会在内存中再占用一大块内存,而是随着循环每次生成一个,每次执行__next__()就会每次返回一个
迭代器协议: 内部含有 __next__ 和 __iter__方法的就是迭代器 -> __iter__方法 位于 Iterable里面,通过调用 __iter__ 方法返回一个迭代器 -> Iterator: 迭代器
- 判断是否是迭代器 -> 判断是否有 __next__ 和 __iter__ 方法
def is_iterator(obj):
list_fn = dir(obj)
iter_result = '__iter__' in list_fn
if iter_result:
iter_fn = dir(obj.__iter__())
iterator_result = '__next__' in iter_fn
if iterator_result:
return '是迭代器'
else:
return '可迭代,但不是迭代器'
else:
return '不可迭代'
print(is_iterator([]))
- 获取迭代器: .__iter__() -> 当可迭代对象调用了 .__iter__() 会返回一个迭代器
iterator = [].__iter__() # <list_iterator object at 0x000001EE4B5C3550> 看到 iterator 单词就应该知道它是一个迭代器
- 查看只属于迭代器的方法 -> dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合,然后取差集。
# print(dir([1,2].__iter__()))
# print(dir([1,2]))
print(set(dir([1, 2].__iter__())) - set(dir([1, 2]))) # {'__next__', '__length_hint__', '__setstate__'}
- __length_hint__() -> 获取迭代器中元素的长度
iterator = [1, 2, 3, 4, 5, 6].__iter__()
print(iterator.__length_hint__()) # 6
- __next__() -> 一个一个的取值 -> 可以不依赖 for 循环挨个取值 -> 如果我们一直取next取到迭代器里已经没有元素了,就会抛出一个异常StopIteration,告诉我们,列表中已经没有有效的元素了。
iterator = [1, 2, 3, 4, 5, 6].__iter__()
print(iterator.__next__()) # 1
print(iterator.__next__()) # 2
print(iterator.__next__()) # 3
- __setstate__ -> 根据索引值指定从哪里开始迭代
iterator = [1, 2, 3, 4, 5, 6].__iter__()
iterator.__setstate__(3)
print(iterator.__next__())
print(iterator.__next__())
print(iterator.__next__())
iterator = [1, 2, 3, 4, 5, 6].__iter__()
iterator.__setstate__(3)
for i in iterator:
print(i)
3. for 循环的执行机制 -> 了解就可以
在执行 for 循环的时候它首先会判断该对象是否是可迭代的,然后再判断是否是迭代器,如果是迭代器再执行迭代器中 __next__方法
4. for 循环 和 迭代器的区别
- for循环: 多个 for 循环 循环一个可迭代对象的时候,for循环会在自身内部生成一个迭代器
lis = [1, 2, 3, 4]
for i in lis:
print(i)
for i2 in lis:
print(i2)
- 迭代器: 如果迭代器里的值都被取过一遍以后(取完了), 那么迭代器再被调用的时候里面的值是空的 -> 因为迭代器里的值只能取一遍,取完就没有了
lis = [1, 2, 3, 4]
iterator = lis.__iter__()
i_lis = list(iterator) # [1, 2, 3, 4] 此时,迭代器里的所有值都给了 list
i_lis2 = list(iterator) # [] 迭代器里的值都被取完了
5. iter() 和 next()
- iter() 等同于 __iter__() next() 等同于 __next__() 在以后日常使用中尽量使用 iter() 和 next(),在这里使用 __iter__() 和 __next__() 是为了说明
- iter(可迭代对象)
lis = [1, 2, 3]
iterator = iter(lis)
# 等同于
iterator = lis.__iter__()
- next(迭代器)
lis = [1, 2, 3]
iterator = iter(lis)
num = next(iterator)
# 等同于
num = iterator.__next__()
5. 总结
- 迭代是访问集合元素的一种方式,迭代器是一个能够记住遍历位置的对象
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问完结束
- 如果想访问一个元素,需要把这个元素前面的所有元素都遍历后,才可以访问
- 凡是可作用于 for 循环的对象都是 Iterable(可迭代)
- 凡是可作用于 __next__() 的函数的对象都是Iterator (迭代器)
- __iter__()函数用于把Iterable(可迭代)容器,变成Iterator(迭代器)
← 进程间通信 - Queue 队列 递归函数 →