15.python的for循环与迭代器、生成器

  在前面学习讲完while循环之后,现在终于要将for循环这个坑填上了。之所以拖到现在是因为for循环对前面讲过的序列、字典、集合都是有效的,讲完前面的内容再来讲for循环会更加容易上手。

  首先,for循环和while循环一样,都是在满足一定条件的时候对其内层的代码进行循环执行。不同的是,while循环判断的是条件,而for判断的是迭代对象。

    Python 中的 for 接受可迭代对象(例如序列或迭代器)作为其参数,每次迭代其中一个元素。

  我们先来看for循环的代码:

a = (1, 2, 3, 4, 5)
for x in a:
    print x

 

  我们以序列中的元祖为例,发现其输出了这些,那么这段代码的逻辑是怎么样的?为了方便大家理解,我画了这样一个图:

  我写了一个收租的小故事,方便大家理解。不知道为什么写的时候感觉眼角有点湿润。

  for循环其实就是不断的去可迭代对象中拿去元素,而可迭代对象在每次迭代的时候都会把指针下移一格,也就是下次再来拿的时候,拿的是下一个。而这是因为可迭代对象有这样行为,才称其为可迭代。

  这个时候我又要问一个问题,在迭代循环结束以后,x的值是否还存在?

  当然还在,都说了作用域是函数的东西,迭代循环并不是函数。按照for循环的思路,x的值是不断更新的,所以在循环结束的时候,x应该等于最后一次迭代的值。以这里为例,x在循环结束的时候,其值应该为5。即x=5。

a = (1, 2, 3, 4, 5)
for x in a:
    print x
print '----',x
print a

 

  

  另外,虽说交租是交了出去自己没有了,但是迭代循环并不会改变a本身,也就是相当于借给别人看一眼,东西还是自己的。

  当然现实中没有这样的福利就是了。

  序列的迭代都和上面的一样,其都是按照索引的顺序依次给出。而字典和集合都是无序的,所以循环得到的顺序和我们代码写的顺序是不同的。但是我在字典篇中说过,字典的无序体现在其保存上,也就是一旦保存以后,其顺序虽然和我们代码写的顺序不同,但也不会每次循环得到的顺序都不同。如果每次循环得到的顺序都不同那要多大工程,浪费多少计算资源,这显然不符合python化繁为简的哲学。

   另外,这里提醒一句,字典循环得到的键,而集合没有键的概念,所以得到的元素。

 


 

 1.迭代器和生成器

   你可能会看到这样的写法:

for x in range(1,5):
    print x

 

  range()是什么鬼,我们先进交换模式看一下先:

  

  直接返回了一个列表,也就是这个函数是快速生产列表的咯,for循环就相当于迭代了列表了咯,这就好理解了。

  还可能会有这个写法:

for x in xrange(1,5):
    print x

   

  xrange()又是什么鬼?

  返回了自己。

  好吧,这里解释一下,什么是迭代器和生成器了。


1.迭代器

  迭代器是一个实现了迭代器协议的对象,Python中的迭代器协议就是有next方法的对象会前进到下一结果,而在一系列结果的末尾是,则会引发StopIteration。

 

   而在for循环中,会自动调用 iter()将我们要迭代的对象转化为可迭代对象,每次循环都会调用 .next() 方法获取新元素,当引发StopIteration错误的时候自动退出循环,这就for循环的内部操作。

  常用的数据类型,如:str、tuple、list、dict、set,都能进行迭代循环,因为其内部都有相应的方法,如list中的:

  所以我们自己也可以创建一个可迭代的类:

class Text():
    def __init__(self,list_input):  #初始化函数
        self.list = list_input
        self.i = 0

    def __iter__(self):
        return self

    def next(self):
        if self.i == len(self.list):    #如果索引到了最后,说明迭代完毕
            self.i = 0  #将索引归0
            raise StopIteration     #触发错误
        #如果索引没到最后
        self.i += 1 #索引先后移一位
        return self.list[self.i - 1]    #取出前一位的值

 

a = Text([1,2,3])
for x in a:
    print x

   这就是迭代器了。

 


2.生成器

  xrange()就是生成器。

  所谓的生成器就是每次调用的时候返回一个对象,而不是一次性在内存中创建,从而达到节约内存的作用。

  而生成器靠yield关键字实现,生成器的编写类似于函数,只不过将函数的return改成了yield:

def scq():
    yield 1
    yield 2
    yield 3
a = scq()
print a.next()
print a.next()
print a.next()

  每次调用a.next()的时候得到的都是不同的值。

  当然我们也可以像函数一样处理它:

  总之,yield的核心在于冻结函数,一旦遇到,冻结这个函数;而return在于结束函数,一旦遇到,返回结果,函数整个退出,下次调用时重新开始执行。

  当然,到了最后一个的时候也会触发错误:

  可以看出,生成器是每次调用的时候生成一个对象,所以生成器比迭代器更节约内存,但也更耗费cpu,因为代码需要运算。不过一般情况下,使用生成器会有更高的效率。

 


  最后补充range和xrange两个函数的用法:

  range和xrange都接受三个参数:

  

  其中start和stop表示开始和结束,同样不包括结束的那个值,后面的只是个分界线而已。当只给一个参数的时候,默认从0开始,即start=0。

  而step表示步长,和序列中的一样,表示走几步执行生成一次。

 


  暂时先写这么多,后面有什么错误和补充的会继续完善。

  参考和转载的文献:戳这里

 

posted @ 2016-05-30 13:12  scolia  阅读(6868)  评论(2编辑  收藏  举报