这是个和多态有关的问题,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__是优先读取的。