Python 迭代器 生成器

迭代器

迭代器是带有next方法的简单对象。迭代器能在一系列的值上进行迭代,当没有值迭代的时候,next方法就会引发StopIteration异常,可迭代对象有一个返回迭代器的__iter__方法,它能像序列一样在for循环中使用

1.创建迭代器

假如一个函数可以一个接一个地计算值,那么与使用列表相比,使用迭代器更通用,简单,高效。迭代器不是一次性获取所有值

class Fibs:
    def __init__(self):
        self.a = 0
        self.b = 1
    def next(self):
        self.a,self.b = self.b,self.a+self.b
        return self.a
    def __iter__(self):
        return self

fibs = Fibs()
for f in fibs:
    if f>1000:
        print f
        break</span>
这个程序的迭代器生成了斐波那契数列,然后查找在数列中比1000大的数中最小的值,输出结果为1597

这个例子说明,一个实现了__iter__方法的对象是可迭代的,一个实现了next方法的对象则是迭代器

2.从迭代器得到序列

可以使用list(迭代器实例)把迭代器转换为序列。

生成器

生成器是一种用普通的函数语法定义的迭代器,它的工作方式可以用例子来很好地展现

1.创建生成器

假设存在一个列表的列表(即列表的元素是列表)。要实现一个函数打印出一个列表中数字

解决的方法如下:

def flatten(nested):
    for sublist in nested:
        for element in sublist:
            yield element

nested = [[1,2],[3,4],[5]]
for num in flatten(nested):
    print num
print list(flatten(nested))
~                                                                                                                                          
~                                                                                                                                          
~                                  
任何包含yield的语句称为生成器,它不返回值,而是每次产生多个值。

2.递归生成器

假设我们不知道列表中子列表的层数,那么我们无法明确知道需要几层嵌套,几个 for循环。这时候可以利用递归的思想来解决:

def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested

if __name__=='__main__':
    nested = [[[1],2],3,4,[5,[6,7]],8]
    print list(flatten(nested))

输出结果为 [1,2,3,4,5,6,7,8]

注意不应该flatten函数中对类似于字符串的对象进行迭代对它们迭代实际上会导致无穷递归,因为一个字符串的第一个元素是另一个长度为1的字符串,而长度为1的字符串的第一个元素是字符串本身

为了处理这种情况,在生成器的开始处添加一个检查语句,代码如下

def flatten(nested):
    try:
        try: nested + ' '
        except TypeError: pass
        else : raise TypeError
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except TypeError:
        yield nested

if __name__=='__main__':
    nested = ['foo',['bar',['baz']]]
    print list(flatten(nested))
输出结果为['foo', 'bar', 'baz']

检查的方法是 试着将传人的对象和一个字符串拼接,看看会不会出现TypeError 出现的话就不是字符串 直接忽略; 如果没有引发一个TypeError,Else子句就会引发一个它自己的TypeError异常,这样会按照原来的样子生成类似字符串的对象

3.生成器方法
send方法,next方法,throw方法,close方法

4.模拟生成器

下面的代码能够不使用yield方法,来模拟实现flatten生成器:

def flatten(nested):
   try:
      try: nested+' '
      except TypeError: pass
      else:raise TypeError
      for sublist in nested:
         for element in flatten(sublist):
            yield element
   except TypeError:
      yield nested

def flatten2(nested ):
   result = []
   try:
      try: nested+' '
      except TypeError: pass
      else:raise TypeError
      for sublist in nested:
         for element in flatten(sublist):
            result.append(element)
   except TypeError:
            result.append(nested)
   return result

以上两个函数完成的功能相同

5.利用生成器来求解八皇后问题

生成器是逐渐产生结果的复杂递归算法的理想实现工具。没有生成器的话,算法就需要一个作为额外参数传递的半成品方案,这样递归调用就可以在这个方案上建立起来。如果使用生成器,那么所有的递归调用只要创建自己的yield部分

#coding:utf-8
# 八皇后问题
# python生成器的方法来完成递归 从而实现N皇后问题

def conflict(state,nextX):            #判断摆放的位置的是否会冲突
    nextY = len(state)
    for i in range(nextY):
        if abs(state[i]-nextX) in (0,nextY-i):
            return True
    return False

def queens(num=8,state=()):  #求合理的摆放位置的生成器 生成的位置用元组表示
    for pos in range(num):
        if not conflict(state,pos):
            if len(state) == num-1:
                yield (pos,)
            else: 
                for result in queens(num,state+(pos,)):
                    yield (pos,) + result

if __name__=='__main__':
    format = "There is %d solutions to solve it"
    value = len(list(queens(8)))
    print format % value
    print "The solutions as follow:" 
    for solution in queens(8):
        print solution          
~                 




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值