导语
可迭代对象和迭代器是常常碰到但又很容易混淆的两个概念,因此今天小编跟你们深刻剖析一下可迭代对象和迭代器的区别。认真看完本文,你将收获:python
- 理解什么是可迭代对象
- 理解检查可迭代对象的方法
- 理解什么是迭代器
- 可迭代对象和迭代器的关系
事不宜迟,咱们立刻开始吧!函数
可迭代对象
要理解可迭代对象,那首先要搞清楚迭代的概念。关于迭代,维基百科是这样子定义的:code
迭代是重复反馈过程的活动,其目的一般是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代获得的结果会被用来做为下一次迭代的初始值。component
从这个定义中,咱们大概能够知道迭代是对某一个过程的重复。其实在程序中,迭代也是相似的,它是一种遍历集合元素的方式,请看下面的示例1。对象
# 示例1 for i in [1,2,3]: print(i)
输出结果:索引
1 2 3
在示例1中,解释器重复地从列表中取出元素并打印,直到遍历结束为止,这就是一个迭代的过程。可见,可迭代对象能够在for循环中遍历元素。ip
那什么样的对象才是一个可迭代对象?事实上,只要实现 __ iter __ 方法或者实现 __ getitem __方法并且其参数从0开始索引,那么该对象就是可迭代对象,请看示例2。字符串
#示例2 class Vector(object): def __init__(self,components): self.components = list(components) def __iter__(self): return iter(self.components) V1 = Vector([1,2,3]) for i in V1: print(i)
输出结果:get
1 2 3
从示例2中可见,Vector类实现了 __ iter __方法,解释器能够从Vector类对象中重复地取出元素并打印。若是要检查某一个对象是否为可迭代对象,其实可使用isinstance( )函数,该函数用于判断对象是否为某一类型,可是用这个函数判断不必定准确(缘由后面会说到)。input
from collections.abc import Iterable print(isinstance(V1,Iterable))#True
若是咱们只是实现了 __ getitem __ ()方法,状况又会怎么样呢?请看示例3。
# 示例3 from collections.abc import Iterable class Vector(object): def __init__(self,components): self.components = list(components) def __getitem__(self,index): return self.components[index] V1 = Vector([1,2,3]) for i in V1: print(i) print(isinstance(V1,Iterable))
输出结果:
1 2 3 Flase
从示例3中可看到,Vector实现了 __ getitem __ 方法,解释器能够对V1进行迭代并打印元素,可是!使用isinstance()判断时,返回的结果竟然是False。明明可使用for循环来迭代元素,为何是判断是Flase呢?事实上,若是可迭代对象只是实现了 __ getitem __ 的话,abc.Iterable是不考虑该方法的,这便致使了isinstance()判断不许确。更准确的方法应该是调用iter()函数,若是该对象不可迭代,就会抛出TypeError的错误。咱们尝试使用iter()来判断一下。
# 示例4 print(iter(V1)) #<iterator object at 0x000001B262E35518> #去掉__getitem__方法后 print(iter(V1)) #TypeError: 'Vector' object is not iterable
从示例4中能够看到,对于可迭代对象,iter()会返回< iterator object at xxxx >。当去掉 __ getitem __ ()方法后再检查时,便抛出TypeError错误。iter()函数用于生成一个迭代器,也就是说能够返回一个迭代器的就是一个可迭代对象。
该对象之因此能迭代,是由于实现了__ iter __ ()方法。当使用for循环时候,解释器会检查对象是否有__ iter __ ()方法,有的话就是调用它来获取一个迭代器。因此没有 __ iter __ ()方法但实现了__ getitem __ (),解释器会建立一个迭代器,尝试从0开始按顺序遍历元素。若是尝试失败,Python便会抛出TypeError错误。
那么Python内置类型中究竟有哪些可迭代对象呢?咱们一块儿盘点一下吧。
- list
- dict
- tuple
- set
- string
其实盘点出来的都是序列,因此说任何序列都是可迭代的对象, 其缘由在于他们至少都会实现__ getittem __ 方法(序列均可以经过索引获取元素)。
迭代器
在介绍可迭代对象时候说到,当使用for循环时候,解释器会检查对象是否有__ iter __ ()方法,有的话就是调用它来获取一个迭代器。那么究竟什么是迭代器呢?
其实迭代器是实现了**__ iter __ 方法和 __ next __ 方法的对象**。__ iter __ 方法用于返回迭代器自己,而 __ next __ 用于返回下一个元素。咱们自定义一个迭代器,以斐波那契数列为例说明一下其内部的执行状况,看示例5。
# 示例5 import itertools class Fib: def __init__(self): self.pre = 0 self.cur = 1 def __iter__(self): return self def __next__(self): p = self.cur self.cur += self.pre self.pre = p return p f = Fib() a = list(itertools.islice(f,0,10)) print(a) #[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
从示例5中__ iter __ ()返回了迭代器对象自己,以便在使用可迭代对象的地方(如for循环中)使用迭代器,而 __ next __ ()则经过计算返回下一个元素。咱们再一块儿看看下面的示例6。
#示例6 >>>s = 'ABCD' >>>it = iter(s) >>>while True:print(next(it)) A B C D --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-4-d09d5cde4495> in <module>() ----> 1 while True:print(next(it)) StopIteration: >>> list(it) [] >>>list(iter(s)) ['A','B','C','D']
在示例6中先定义一个字符串的可迭代对象,经过iter()函数返回一个迭代器(会自动调用对象的__ iter __ 方法),而后在循环中经过next()取值并打印(会自动调用对象 __ next __ ()方法),经过next()方法一个个地遍历可迭代对象中的元素,当遍历结束,便会抛出StopIteratioin异常,这时迭代器也没用了,若是要再次迭代,就要使用iter()函数从新构建迭代器。
经过示例5和示例6,咱们可知道迭代器是一个能够记住遍历位置的对象,其内部有一个状态用于记录迭代所在的位置,以便下次迭代时候能取出正确的元素。迭代器就像一个懒人同样,当你须要数据时候才会返回给你,不然就在等待下一次的调用。
若是要检查某个对象是否为迭代器,最好的方式是使用isinstance( )函数,见示例7。
# 示例7 from collections.abc import Iterator f = Fib() print(isinstance(f,Iterator)) #True
好了,说了那么多,究竟迭代器哪些用处呢?其实在Python语言内部,迭代器用于支持:
- for 循环
- 构建和扩展集合类型
- 逐行遍历文本文件
- 列表推导、字典推导和集合推导
- 元组拆包
- 调用函数时,使用*拆包
可迭代对象和迭代器的关系
-
可迭代对象不必定是迭代器,迭代器必定是可迭代对象。由于迭代器必定会实现 __ iter __ 方法,而可迭代对象尽管实现了 __ iter __ 也不必定实现 __ next __方法。
-
Python 从可迭代对象中获取迭代器,根据示例6的例子,咱们知道先是使用iter()函数在迭代对象中获取迭代器,而后使用next()来获取下一个元素,关系以下图所示。
总结
- 可迭代对象实现了 __ iter __ 方法或者实现 __ getitem __方法并且其参数从0开始索引。
- 使用iter()函数判断可迭代对象更准确
- 任何序列都是可迭代对象
- 迭代器对象实现了 __ iter __ 和 __ next __方法。
- 迭代器是一个能够记住遍历位置的对象,其内部有一个状态用于记录迭代所在的位置,以便下次迭代时候能取出正确的元素
- 检查对象是否为迭代器最好的方式是调用isinstance()方法。
以上就是小编今天跟你们分享的内容了,若是有什么疑问记得联系小编哦~
公众号:CVpython,专一于分享Python和计算机视觉,咱们坚持原创,不按期更新,但愿文章对你有帮助,快点扫码关注吧。