网络上好多教程都说实现了 __iter__() 和 __next__() 方法的对象就是迭代器, 但是这种说法过于模糊了, 总会让初学者创建出有问题的迭代器.

# 查看列表和列表迭代器,发现它们其实类型并不一样
type([]) # list
type(iter([])) # list_iterator

# 可以认为 列表对象的 __iter__() 方法 返回了一个 list_iterator 对象.

# 而 list_iterator 并不是列表的子类
type(iter([])).mro()
# [list_iterator, object]
   # 看上面的代码, list_iterator 就是一个普通的类
   # 定义方式类似于 class list_iterator:
为什么列表的 __iter__() 没有返回 self , 而是返回了一个新的对象?

返回新对象的好处是 : 能够确保一个迭代器实例只能被迭代一遍, 而且迭代器不会影响创建迭代器的对象的内容 (即不能影响 iter(obj) 里的 obj ).

 

比如一个列表迭代器只能被迭代一次, 而一个列表能被迭代无数次

l = [1]
l_iter = iter(l)
for i in l_iter:
   print(i)
# 1

for i in l_iter:
   print(i)
# 空的, l_iter 只能被迭代一次.

# 注意:创建迭代器的列表对象 l 没有被改变
 

创建类似的迭代器
所以我们想要实现类似的迭代器,就要按如下语法创建

class N:
   def __init__(self,n):
       self.n = n

   def __iter__(self):


       # 我们不返回原本的对象, 而是根据需要迭代的数据,创建一个新的迭代器对象
       class N_iterator:
           def __init__(self, n):
               self.n = n
               self.i = 0

           def __iter__(self):
               return self

           def __next__(self):
               i = self.i
               if i < self.n:
                   self.i += 1
                   return i
               else:
                   raise StopIteration('迭代结束!')

       return N_iterator(self.n)
这样做的好处是我们自定义的可迭代对象和Python内置的可迭代对象的行为变得一致了.

n = N(10)
n_iter = iter(n)


for i in n:
   print(i)
# n 可以多次迭代

for i in n_iter:
   print(i)
# n_iter 只能被迭代一次