【Python】迭代器(iterator) vs 生成器(generator)

迭代器(iterator)

在介绍迭代器之前还有一种iterable对象需要简单的说明。对于iterator和iterable是两个不同的概念。

iterable

  • iterable是含有__iter__方法或者__getitem__ 的一个对象,当你想实现一个iterable对象的时候,通过实现__iter__方法返回一个iterator而不是iterable。检查一个对象是不是iterable对象一般是通过catch异常的方式去检查,虽然这个方式有点挫;另外一种是检查是否是容器类中的Itreaable对象if isinstance(e, collections.Iterable)。对于一个iterable的对象可以通过调用iter方法返回一个iterator对象,然后进行for loop访问。
class Iterable_:
   def __iter__(self):
       return iter([1, 2, 3]) 
it = iter((Iterable_()))
for i in it: 
    print "iterable:" + str(i)

#输出
iterable:1
iterable:2
iterable:3

iterator

  • 迭代器肯定是iterable类型的对象,它是包含有next(Python 2) 方法或者__next__(Python 3) 方法和__iter__(返回self)方法的一个特殊对象,可以对这样一个对象进行for loop循环访问。
  • 对于实现next方法需要注意的是,当没有下一个元素的时候必须抛出StopIteration异常
  • 当遍历一个迭代器的时候,它会修改内部状态,导致你只能向前获取下一个元素,不能通过迭代器访问后面一个元素;也就是说当你通过迭代器访问了一个元素以后,在当前循环中不能后退继续访问该元素了,除非你重新生产迭代器对象进行遍历。
  • 另外需要注意的是在迭代器中next方法是return下一个元素的值,不像下面介绍的生成器yield一个元素。
class Iterator_:
   def __init__(self, s, e): 
       self.current = s 
       self.end = e 
   def __iter__(self):
       return self
   def next(self):
       if self.current < self.end:
           self.index = self.current
           self.current += 1
           return self.index
       else:
           raise StopIteration
it = Iterator_(5, 8)
for i in it: 
    print "iterator:" + str(i)
#never print
for i in it: 
    print "second iterator:" + str(i)
#print again
it = Iterator_(5, 8)
for i in it: 
    print "second iterator:" + str(i)
#输出
iterator:5
iterator:6
iterator:7
second iterator:5
second iterator:6
second iterator:7

生成器(generator)


对于一个生成器它一定是一个迭代器,可以通过for loop进行访问其中的元素,但是一个迭代器却很明显的不一定是生成器
定义迭代器有两种方式,第一个是使用yield关键词,另外一个是生成器表达式"()"。对于一个方法在方法体里 加上yield关键词就变成了生成器。yield作用就是返回一个生成器,它会保存当前函数状态,记录下一次函数被调用next的时候运行状态。当函数没有下一次运行状态的时候,再继续调用next方法,这个时候StopIteration异常就被抛出。
print "generator"
#first way 
my_generator = (x for x in range(3))
for i in my_generator:
    print i
#second way
def Generator_(l):
   n = 0 
   size = len(l)
   while n < size:
       yield l[n]   
       n += 1

ge = Generator_([1, 2, 3]) 
for g in ge: 
    print "generator:" + str(g)

因为生成器是一个迭代器,所以迭代器具有的特性,生成器肯定会具有的。比如只能向前遍历等。当然除了迭代器特性之外,生成器还有自己的方法。比如send方法等。通过send可以定义当前生成器中的值。

你可能感兴趣的:(python,迭代器,生成器)