什么是可迭代的对象?
可迭代的对象,Iterable object,即可以用for循环的对象。
Iterable:
- 一类是:list、tuple、dict、set、str
- 二类是:生成器(generator)(生成器都是可迭代对象),包含生成器和带yield的generator function
迭代器
迭代器是实现迭代器协议的对象,该协议由__iter __()
和__next __()
方法组成。
换句话说,如果一个对象实现了__iter __()
和__next __()
这两个方法,那么这个对象就是迭代器。
又或者说,如果一个对一个对象使用next()
方法,会返回一个元素,那么这个对象就是一个迭代器。因为next()
函数其实就是先调用__iter __()
,再调用__next __()
这两个方法来实现的。
注意,next()
函数的实现并不是直接调用__next __()
这个方法,而是先调用__iter __()
返回对象本身,再调用__next __()
。至于为什么一定要先调用__iter __()
返回对象本身,我目前也不太了解。我也看到有一些文章说只需要实现__next __()
这个方法即可,我会再继续研究这个问题。
迭代器有以下特点:
- 迭代器是代表数据流的对象。
- 它一次返回一个元素的数据。
- 它必须支持
__next __()
的方法,该方法不带任何参数,并且始终返回流的下一个元素(或者这穷尽所有元素之后,返回StopIteration
错误)。例如,如果a
是一个迭代器,那么a.__next__()
会返回下一个元素。其实next(a)
就是后台调用了a.__next__()
。所以可以说,迭代器必须可以支持next(a)
。 - 如果流中没有其他元素,则
__next __()
必须引发StopIteration
异常。 - 迭代器不必一定是有限的。一个生成无限数据流的迭代器是完全合理的。
可迭代对象
可迭代对象 = 任何可以支持for loop
循环的对象 = 任何可以通过iter()
返回一个迭代器的对象。
比如列表就是一个可迭代对象。
a=[1,2,3,4]
for i in a:
print(i) # 1,2,3,4
b = iter(a)
print(b) # <list_iterator object at 0x2aaaaabe4c50>
# list支持for 循环,而且也可以通过iter()返回一个迭代器,所以list是一个可迭代对象
print(next(a)) # TypeError: 'list' object is not an iterator
print(next(a)) # 1
# list不支持next()函数,所以list不是迭代器。不过list是可迭代对象,所以通过iter()函数可以把它变成迭代器。
可迭代对象有2种实现方式:
- 任何对象,如果它具有一个
__iter__
方法,并且这个方法会返回一个迭代器,那么这个对象就是可迭代对象。 - 任何对象,如果它具有一个
__getitem__
方法,并且这个方法可以接收从0开始到一系列索引值来返回相应的元素(当索引值不可用时候,可以返回IndexError
错误),那么这个对象就是可迭代对象。
class Ite:
def __init__(self):
self.a = [1, 2, 3, 4]
self.len = len(self.a)
print(self.len)
def __getitem__(self, i):
if (0 <= i < self.len) and type(i) is int:
return self.a[i]
else:
raise IndexError
a = Ite()
print(a[0]) # 1
for i in a:
print(i) # 1,2,3,4
class Ite1:
def __init__(self):
self.a = Ite2() # 可迭代对象
self.b = iter(self.a) # 迭代器
def __iter__(self):
return self.b
a = Ite1()
for i in a:
print(i) # 1,2,3,4
print(a[0]) # TypeError: 'Ite1' object is not subscriptable
# 通过__iter__实现的可迭代对象,如果没有__getitem__()方法是没法通过索引值来获取数据的。
所有的迭代器都属于可迭代对象,因为所有的迭代器都有一个__iter__
方法,并且这个方法会返回迭代器自身,上面已经讲过。