X Tutup
>你竟任着刚硬不悔改的心,为自己积蓄忿怒,以致神震怒,显他公义审判的日子来到。他必照各人的行为报应各人。凡恒心行善,寻求荣耀、尊贵和不能朽坏之福的,就以永生报应他们;惟有结党不顺从真理,反顺从不义的,就以忿怒、恼恨报应他们。(ROMANS 2:7-8) #迭代 Bill正在介绍他的项目,嘴里不断蹦出“loop、iterate、traversal、recursion”这些单词,夹杂在汉语汇总。旁边的小白们,都瞠目结舌,“不明觉厉”,心中的敬佩油然而生, 其实,Bill不是真正的大牛,我见过真牛的,他们绝对不会这么说的,他们通常总是轻描淡写,不管我认为多么麻烦的,他们都是举重若轻地解决: “你就循环一下,然后来个迭代”, “最后只要花几分钟写个递归就好了” 然后再问“这个你懂吗?”。 哦,这就是真正牛X的程序员。虽然还是不懂。 所以,我们还是老老实实地先搞清楚这些名词再说别的: - 循环(loop),指的是在满足条件的情况下,重复执行同一段代码。比如,while语句。 - 迭代(iterate),指的是按照某种顺序逐个访问列表中的每一项。比如,for语句。 - 递归(recursion),指的是一个函数不断调用自身的行为。比如,以编程方式输出著名的斐波纳契数列。 - 遍历(traversal),指的是按照一定的规则访问树形结构中的每个节点,而且每个节点都只访问一次。 对于这四个听起来高深莫测的词汇,其实前面,已经涉及到了一个——循环(loop),本节主要介绍一下迭代(iterate),在网上google,就会发现,对于迭代和循环、递归之间的比较的文章不少,分别从不同角度将它们进行了对比。这里暂不比较,先搞明白Python中的迭代。 当然,迭代的话题如果要说起来,会很长,本着循序渐进的原则,这里介绍比较初级的。 ##逐个访问 在Python中,访问对象中每个元素,可以这么做:(例如一个list) >>> lst = ['q', 'i', 'w', 's', 'i', 'r'] >>> for i in lst: ... print i, #Python 3: print(i, end='') ... q i w s i r 除了这种方法,还可以这样: >>> lst_iter = iter(lst) #对原来的list实施了一个iter() >>> lst_iter.next() #Python 3,请用:lst_iter.__next__() 'q' >>> lst_iter.next() 'i' >>> lst_iter.next() 'w' >>> lst_iter.next() 's' >>> lst_iter.next() 'i' >>> lst_iter.next() 'r' >>> lst_iter.next() Traceback (most recent call last): File "", line 1, in StopIteration `iter()`是一个内建函数,其含义是: >>> help(iter) Help on built-in function iter in module builtins: iter(...) iter(iterable) -> iterator iter(callable, sentinel) -> iterator Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel. `iter()`函数返回的是一个迭代器对象。关于迭代器对象,本教程会有专门讲授。 >>> type(lst_iter) #Python 3: 所有的迭代器对象,在Python 2中有一个`next()`方法,在Python 3中,相应的修改为了`__next__()`。所以使用不同版本,要注意一下这个方法名称的变更。 迭代器,当然是可迭代的。本教程已经介绍过如果判断一个对象是否为可迭代对象的方法了。 在上面的举例中,`next()`或者`__next__()`就是要获得下一个元素,但是做为一名优秀的程序员,最佳品质就是“懒惰”,当然不能这样一个一个地敲啦,于是就: >>> while True: ... print lst_iter.next() #Python 3: print(lst_iter.__next__()) ... Traceback (most recent call last): File "", line 2, in StopIteration 先不管错误,再来一遍。 >>> lst_iter = iter(lst) >>> while True: ... print lst_iter.next() #Python 3: print(lst_iter.__next__()) ... q i w s i r Traceback (most recent call last): #读取到最后一个之后,停止循环 File "", line 2, in StopIteration 看上面的演示的例子会发现,如果用for来迭代,当到末尾的时候,就自动结束了,不会报错。如果用`next()`或者`__next__()`,当最后一个完成之后,它不会自动结束,还要向下继续,但是后面没有元素了,于是就报一个称之为StopIteration的信息(名叫:停止迭代,这分明是警告)。 还要关注迭代器对象的另外一个特点,当对象`lst_iter`被迭代结束,即每个元素都读取了一遍之后,指针就移动到了最后一个元素的后面。如果再访问,指针并没有自动返回到首位置,而是仍然停留在末位置,所以报StopIteration,想要再开始,需要重新载入迭代对象。所以,当我在上面重新进行迭代对象赋值之后,又可以继续了。 ##文件迭代器 现在有一个文件,名称:208.txt,其内容如下: Learn python with qiwsir. There is free python course. The website is: http://qiwsir.github.io Its language is Chinese. 用迭代器来操作这个文件,我们在前面讲述文件有关知识的时候已经做过了,无非就是: >>> f = open("208.txt") >>> f.readline() #读第一行 'Learn python with qiwsir.\n' >>> f.readline() #读第二行 'There is free python course.\n' >>> f.readline() #读第三行 'The website is:\n' >>> f.readline() #读第四行 'http://qiwsir.github.io\n' >>> f.readline() #读第五行,也就是这真在读完最后一行之后,到了此行的后面 'Its language is Chinese.\n' >>> f.readline() #无内容了,但是不报错,返回空。 '' 以上演示的是用readline()一行一行地读。当然,在实际操作中,我们是绝对不能这样做的,一定要让它自动进行,比较常用的方法是: >>> for line in f: #这个操作是紧接着上面的操作进行的 ... print line, #Python 3: print(line) ... #没有打印出什么东西 这段代码之所没有打印出东西来,是因为经过前面的操作,指针已经移到了最后了。这就是迭代的一个特点,要小心指针的位置。 >>> f = open("208.txt") #从头再来 >>> for line in f: ... print line, #Python 3: print(line,end='') ... Learn python with qiwsir. There is free python course. The website is: http://qiwsir.github.io Its language is Chinese. 上面过程用`next()`或者`__next__()`也能够读取。 >>> f = open("208.txt") >>> f.next() #Python 3: f.__next__() 'Learn python with qiwsir.\n' >>> f.next() 'There is free python course.\n' >>> f.next() 'The website is:\n' >>> f.next() 'http://qiwsir.github.io\n' >>> f.next() 'Its language is Chinese.\n' >>> f.next() Traceback (most recent call last): File "", line 1, in StopIteration 如果用`next()`或者`__next__()`,就可以直接读取每行的内容。这说明文件是天然的可迭代对象,不需要用iter()转换了。 再有,我们用for来实现迭代,在本质上,就是自动调用`next()`或者`__next__()`,只不过这个工作,已经让for偷偷地替我们干了,到这里,列位是不是应该给for取另外一个名字:它叫雷锋。 其实,迭代器远远不止上述这么简单,下面我们随便列举一些,在Python中还可以这样得到迭代对象中的元素。 >>> list(open('208.txt')) ['Learn python with qiwsir.\n', 'There is free python course.\n', 'The website is:\n', 'http://qiwsir.github.io\n', 'Its language is Chinese.\n'] >>> tuple(open('208.txt')) ('Learn python with qiwsir.\n', 'There is free python course.\n', 'The website is:\n', 'http://qiwsir.github.io\n', 'Its language is Chinese.\n') >>> "$$$".join(open('208.txt')) 'Learn python with qiwsir.\n$$$There is free python course.\n$$$The website is:\n$$$http://qiwsir.github.io\n$$$Its language is Chinese.\n' >>> a,b,c,d,e = open("208.txt") >>> a 'Learn python with qiwsir.\n' >>> b 'There is free python course.\n' >>> c 'The website is:\n' >>> d 'http://qiwsir.github.io\n' >>> e 'Its language is Chinese.\n' 上述方式,在编程实践中不一定用得上,只是向读者展示一下,并且要明白,可以这么做,不是非要这么做。 最后透露,字典和元组都可以写成类似列表解析式的样式,也可以迭代,读者不妨摸索一下。 ------ [总目录](./index.md)   |   [上节:文件(2)](./127.md)   |   [下节:练习](./129.md) 如果你认为有必要打赏我,请通过支付宝:**qiwsir@126.com**,不胜感激。
X Tutup