构build一个基本的Python迭代器
如何在Python中创build一个迭代函数(或迭代器对象)?
 python中的迭代器对象符合迭代器协议,这意味着它们提供了两个方法: __iter__()和next() 。  __iter__返回迭代器对象,并在循环开始时隐式调用。  next()方法返回下一个值,并在每个循环增量中隐式调用。  next()会在没有更多值返回时引发StopIterationexception,这是通过循环结构隐式捕获来停止迭代的。 
这是一个简单的计数器例子:
 class Counter: def __init__(self, low, high): self.current = low self.high = high def __iter__(self): return self def next(self): # Python 3: def __next__(self) if self.current > self.high: raise StopIteration else: self.current += 1 return self.current - 1 for c in Counter(3, 8): print c 
这将打印:
 3 4 5 6 7 8 
使用生成器可以更容易地编写代码,如前面的答案中所述:
 def counter(low, high): current = low while current <= high: yield current current += 1 for c in counter(3, 8): print c 
打印的输出将是相同的。 在引擎盖下,生成器对象支持迭代器协议,并且做类似于类Counter的东西。
David Mertz的文章“ 迭代器和简单生成器 ”是一个很好的介绍。
有四种方法来构build迭代函数:
- 创build一个生成器(使用yield关键字 )
- 使用生成器expression式( genexp )
-  创build一个迭代器(定义__iter__和__next__(或Python 2.x中的next))
-  创build一个Python可以自己迭代的函数( 定义__getitem__)
例子:
 # generator def uc_gen(text): for char in text: yield char.upper() # generator expression def uc_genexp(text): return (char.upper() for char in text) # iterator protocol class uc_iter(): def __init__(self, text): self.text = text self.index = 0 def __iter__(self): return self def __next__(self): try: result = self.text[self.index].upper() except IndexError: raise StopIteration self.index += 1 return result # getitem method class uc_getitem(): def __init__(self, text): self.text = text def __getitem__(self, index): result = self.text[index].upper() return result 
要看到所有四种方法在行动:
 for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem: for ch in iterator('abcde'): print ch, print 
其结果是:
 ABCDE ABCDE ABCDE ABCDE 
注意 :
 两个生成器types( uc_gen和uc_genexp )不能reversed() ; 普通迭代器( uc_iter )将需要__reversed__魔术方法(它必须返回一个新的迭代器向后)。 而getitem iteratable( uc_getitem )必须有__len__魔术方法: 
  # for uc_iter def __reversed__(self): return reversed(self.text) # for uc_getitem def __len__(self) return len(self.text) 
要回答Panic上校关于无限懒惰评估迭代器的第二个问题,下面是使用上述四种方法中的每一个的例子:
 # generator def even_gen(): result = 0 while True: yield result result += 2 # generator expression def even_genexp(): return (num for num in even_gen()) # or even_iter or even_getitem # not much value under these circumstances # iterator protocol class even_iter(): def __init__(self): self.value = 0 def __iter__(self): return self def __next__(self): next_value = self.value self.value += 2 return next_value # getitem method class even_getitem(): def __getitem__(self, index): return index * 2 import random for iterator in even_gen, even_genexp, even_iter, even_getitem: limit = random.randint(15, 30) count = 0 for even in iterator(): print even, count += 1 if count >= limit: break print 
其结果(至less对我的样品运行):
 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 
首先itertools模块对于迭代器很有用的所有情况都是非常有用的,但是在这里你只需要在python中创build一个迭代器:
产量
这不是很酷吗? 产量可以用来取代函数中的正常返回 。 它返回的对象是一样的,但不是销毁状态和退出,而是保存当你想要执行下一个迭代的状态。 下面是一个直接从itertools函数列表中取出的例子:
  def count(n=0): while True: yield n n += 1 
正如函数描述中所述(它是itertools模块的count()函数),它将生成一个迭代器,它返回从n开始的连续整数。
发生器expression式是一个完整的蠕虫(真棒蠕虫!)。 它们可以用来代替列表理解来节省内存(列表parsing在内存中创build一个列表,在使用后会被销毁,如果没有分配给一个variables,但是生成器expression式可以创build一个生成器对象…这是一个奇特的方式说迭代器)。 这是一个生成器expression式定义的例子:
 gen = (n for n in xrange(0,11)) 
这与我们上面的迭代器定义非常相似,除了全部范围预定在0和10之间。
我刚刚发现xrange() (惊讶我以前没见过…),并将其添加到上面的示例。 xrange()是range()的可迭代版本,其优点是不会预build列表。 如果你有一个巨大的数据集来迭代,只有这么多的内存来完成,那将是非常有用的。
 我看到你们中的一些人在__iter__ return self 。 我只是想指出, __iter__本身可以是一个生成器(从而消除__next__和提高StopIterationexception的需要) 
 class range: def __init__(self,a,b): self.a = a self.b = b def __iter__(self): i = self.a while i < self.b: yield i i+=1 
当然这里也可以直接生成一个生成器,但是对于更复杂的类,它可能是有用的。
 这个问题是关于可迭代的对象,而不是迭代器。 在Python中,序列也是可迭代的,所以制作一个可迭代的类的一个方法就是使它的行为像一个序列,即赋予它__getitem__和__len__方法。 我已经在Python 2和3上testing了这个。 
 class CustomRange: def __init__(self, low, high): self.low = low self.high = high def __getitem__(self, item): if item >= len(self): raise IndexError("CustomRange index out of range") return self.low + item def __len__(self): return self.high - self.low cr = CustomRange(0, 10) for i in cr: print(i) 
 这是一个没有yield的迭代函数。 它使用了iter函数和一个闭包,它将它的状态保存在python 2的封闭范围内的一个可变( list )中。 
 def count(low, high): counter = [0] def tmp(): val = low + counter[0] if val < high: counter[0] += 1 return val return None return iter(tmp, None) 
 对于Python 3,封闭状态在封闭范围内保持不变, nonlocal局部范围在本地范围内用于更新状态variables。 
 def count(low, high): counter = 0 def tmp(): nonlocal counter val = low + counter if val < high: counter += 1 return val return None return iter(tmp, None) 
testing;
 for i in count(1,10): print(i) 1 2 3 4 5 6 7 8 9