迭代器协议规定:对象内部必须提供一个__next__方法,对其执行该方法要么返回迭代器中的下一项(可以暂时理解为下一个元素),要么就引起一个Stopiteration异常以终止迭代。(当所有元素被取干净后其实内部就会自动触发Stopiteration

  可迭代对象是指对象内部必须提供一个__iter__方法,并且只要是可迭代对象那么就可以通过__iter__方法创造出该对象所专属的迭代器。

  注意:

   1.迭代器(Iterator):必须有__next__方法才能被叫做迭代器。

   2.可迭代对象(Iterable):必须有__iter__方法才能被叫做可迭代对象

  两者之间的关系:

   1.迭代器是可迭代对象,

   2.可迭代对象不一定是迭代器,

初识迭代器

什么是迭代器

  迭代器指的是迭代取值的一种工具。

  迭代指的是一个重复的过程,每次重复都必须基于上一次的结果而继续,单纯的重复并不是迭代。

# ==== 迭代与非迭代的区别 ====

count = 0
while count < 5:
    print(count)
    count += 1
# 以上的每一次重复动作都是基于上一次重复动作,可以称之为迭代。
while 1:
    input(">>>")
# 以上不可称之为迭代,下一次的重复动作与上一次没有任何关系。

为什么要有迭代器

  对于列表等具有索引的数据类型来说,取出他们的值可以使用索引。 而对于字典集合等等不提供索引的数据类型来说,Python必须为其提供一种能够不依赖于索引的取值方式。这种方式就被称为迭代器。

怎么使用迭代器

  迭代器可以通过循环进行取值。下面的章节将详细介绍迭代器及其内部原理,学完本章节你就能随心所欲的驾驭迭代器了。

迭代器详解

迭代器和可迭代对象的区别与关系

  1.迭代器(Iterator):必须有__next__方法才能被叫做迭代器。

  2.可迭代对象(Iterable):必须有__iter__方法才能被叫做可迭代对象

  基于这两句话,我们可以为学过的数据类型做一个区分:

[].__iter__() # list具有 __iter__ 方法,是可迭代对象
[].__next__() # list不具有 __next__方法,不是迭代器
# AttributeError: 'list' object has no attribute '__next__'

  他们的关系在于:

  通过可迭代对象的__iter__方法。可以为其创造一个专属的迭代器。

  示例如下:

# ==== 迭代器和迭代对象的区分 ====
from collections.abc import Iterable  # 可以用于判断是否是可迭代对象
from collections.abc import Iterator  # 可以用于判断是否是迭代器

li = [1, 2, 3, 4, 5]
# isinstance 可以用来判断一个对象是否属于另一个对象
print(isinstance(li, Iterable))  # True 判断是否属于可迭代对象,说明具有__iter__方法
print(isinstance(li, Iterator))  # False 判断是否属于迭代器,说明没有__next__方法。

li_iterator = iter(li)  # iter方法就是调用对象内置的__iter__方法。
print(li_iterator)  # <list_iterator object at 0x0000021AC6BB3AF0>
print(isinstance(li_iterator, Iterable))  # True
print(isinstance(li_iterator, Iterator))  # True 
# 可以看到。iter方法就是为可迭代对象li创建出了一个专属迭代器。

数据类型迭代类型一览

  我们可以通过导入collections.abs下的包或者手动输入每种数据类型查看是否具有__next__方法的方式做一个总结:

# ==== 实验过程 ====
from collections.abc import Iterable  # 可以用于判断是否是可迭代对象
from collections.abc import Iterator  # 可以用于判断是否是迭代器

st = "123"
print(isinstance(st,Iterable)) # True
print(isinstance(st,Iterator)) # False

li = [1,2,3]
print(isinstance(li,Iterable)) # True
print(isinstance(li,Iterator)) # False

tu = (1,2,3)
print(isinstance(tu,Iterable)) # True
print(isinstance(tu,Iterator)) # False

di = {"k1":"v1"}
print(isinstance(di,Iterable)) # True
print(isinstance(di,Iterator)) # False

se = {1,2,3}
print(isinstance(se,Iterable)) # True
print(isinstance(se,Iterator)) # False

with open(file="test.text",mode="w",encoding="utf-8") as f:
    print(isinstance(f, Iterable))  # True
    print(isinstance(f, Iterator))  # True
# === 了解 === Ps:以下创建方式均为创建出经过优化的可迭代对象。并非迭代器,更并非生成器。

ra = range(1,11)
print(isinstance(ra,Iterable)) # True
print(isinstance(ra,Iterator)) # False

di_keys = di.keys()
print(isinstance(di_keys,Iterable)) # True
print(isinstance(di_keys,Iterator)) # False

di_values = di.values()
print(isinstance(di_values,Iterable)) # True
print(isinstance(di_values,Iterator)) # False

di_items = di.items()
print(isinstance(di_items,Iterable)) # True
print(isinstance(di_items,Iterator)) # False

se_fro = frozenset(se)
print(isinstance(se_fro,Iterable)) # True
print(isinstance(se_fro,Iterator)) # False

  Ps:关于什么叫做经过优化的可迭代对象。会在结束迭代器和生成器的学习后专门开辟一章节来讲。

  五大基本容器数据类型(listtupledictsetstr)等都是属于可迭代对象。本身并不属于迭代器。

  文件句柄对象本身是属于迭代器。

  此外,range()方法产生的数据类型是属于经过优化的可迭代对象。 以及,dictkeysitemsvalues等方法产生的数据类型也是属于经过优化的可迭代对象。

循环与迭代器

while循环取值与迭代器的作用体现

  迭代器的作用在于:对于没有索引的数据类型,对其遍历取值必须通过迭代器下的__next__方法来完成。 并且迭代器中的所有值一旦被取出来,该迭代器将不能被二次应用。

# ==== 迭代器的多次迭代示例 ====
# 方式1 : 针对具有索引的数据类型取值,可以不依赖于迭代器
li = [1,2,3,4,5]
index = 0
while index < len(li):
    print(li[index])
    index += 1
print("针对具有索引的数据类型取值完毕 ---")


# 方式2 :针对不具有索引的数据类型取值,必须依赖迭代器下的__next__方法。
dic = dict(k1="v1",k2="v2",k3="v3")
dic_ator = dic.__iter__() # 创建出专属迭代器,迭代器具有__next__方法
while 1:
    try:
        print(dic_ator.__next__())
        # 或者用 next(li_ator)
    except Exception as e:
        breakprint(" ----> 第二次取值")

while 1:
    try:
        print(dic_ator.__next__())
        # 或者用 next(li_ator)
    except Exception as e:
        break# ==== 执行结果 ==== Ps:可以看到。一个迭代器将所有值全部取出后,再对其进行遍历已经取不出值了。
"""
1
2
3
4
5
针对具有索引的数据类型取值完毕 ---
k1
k2
k3
 ----> 第二次取值
"""
迭代器的多次迭代示例

相关文章:

  • 2022-12-23
  • 2022-01-15
  • 2021-10-20
  • 2022-01-29
  • 2022-12-23
  • 2022-12-23
  • 2022-03-05
  • 2022-02-12
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-04
  • 2022-03-09
相关资源
相似解决方案