淘先锋技术网

首页 1 2 3 4 5 6 7

什么是可迭代的对象?

可迭代的对象,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种实现方式:

  1. 任何对象,如果它具有一个__iter__方法,并且这个方法会返回一个迭代器,那么这个对象就是可迭代对象
  2. 任何对象,如果它具有一个__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__方法,并且这个方法会返回迭代器自身,上面已经讲过。

生成器