【Python】__iter__和__getitem__区别

这是个和多态有关的问题,Python中关于迭代有两个概念,第一个是Iterable,第二个是Iterator,协议规定Iterable的__iter__方法会返回一个Iterator, Iterator的__next__方法(Python 2里是next)会返回下一个迭代对象,如果迭代结束则抛出StopIteration异常。
同时,Iterator自己也是一种Iterable,所以也需要实现Iterable的接口,也就是__iter__,这样在for当中两者都可以使用。

我的理解是,如果这个对象被for时,会首先调用__iter__方法返回一个iterator,然后再对这个iterator循环调用__next__方法,直到碰到StopIteration时则停止退出。

如果for的对象没有__iter__方法,则无法获得一个迭代器,那么就会报错,但是,如果这个类实现了__getitem__方法,会从0开始依次读取相应的下标,直到发生IndexError为止,str类就没有实现了_iter_方法,所以我们可以for一个str对象,让它的每一个字母都打印输出。

__getitem__

单独实现这个魔法函数,可以让这个类成为一个可迭代的对象,并且可以通过使用下标获取类中元素值下标的元素

class Library(object):
    def __init__(self):
        self.books = [1, 2, 3]
        self.index = -1

    def __getitem__(self, i):
        return self.books[i]

    # def __iter__(self):
    #     return self
    # #
    # def __next__(self):
    #     self.index += 1
    #     if self.index > len(self.books)-1:
    #         raise StopIteration()
    #     return self.books[self.index]


l = Library()
print(l[1])
for i in l:
    print(i)

__iter__

这个是返回一个可迭代的对象,如果一个类实现了这个魔法函数,那么这个类就是可迭代对象,并且实现了__next__这个魔法函数的话,可以通过for循环遍历;__next__如果单独实现了这一个魔法函数,只能通过next()调用

class Library(object):
    def __init__(self):
        self.books = [1, 2, 3]
        self.index = -1

    # def __getitem__(self, i):
    #     return self.books[i]

    def __iter__(self):
        return self
    # #
    def __next__(self):
        self.index += 1
        if self.index > len(self.books)-1:
            raise StopIteration()
        return self.books[self.index]


l = Library()
# print(l[1])
print(next(l))
for i in l:
    print(i)

当两者同时存在时

class Library(object):
    def __init__(self):
        self.books = [1, 2, 3]
        self.index = -1

    def __getitem__(self, i):
        return self.books[i]

    def __iter__(self):
        return self
    # #
    def __next__(self):
        self.index += 1
        if self.index > len(self.books)-1:
            raise StopIteration()
        return self.books[self.index]


l = Library()
print(l[1])
print(next(l))
for i in l:
    print(i)

上述代码中的print(l[1])会进入到__getitem__,后面的for则直接进入的是__iter__函数,也就意味着__iter__是优先读取的。

你可能感兴趣的:(Python)