Python难点解析---初级篇3.迭代(可迭代、迭代器、生成器)

什么是迭代

Wiki定义:是重复反馈过程的活动,其目的是为了接近并到达所需的目标或结果。

在程序中,迭代是一种遍历集合元素的方式,我们可以通过索引值递增来遍历集合元素,而迭代是遍历集合元素另一种方式。

下面是使用索引来进行遍历集合元素的方式:

val = [1,2,3,4,5]
for i in range(len(val)):
    retVal = val[i]

这种方式在C++中很常见,在Python中我们可以用更简洁的语法来进行遍历,也就是迭代

三个关键字

说到迭代,在Python里就会提到下面三个关键词:

  • Iterable(可迭代)
  • iterator(迭代器)
  • generator(生成器)

这三个关键字,可能从一开始的某段代码你就接触到了,只是你没有发觉,代码是这样的。

val = [1,2,3,4,5]
for i in val:
    print i

上面这个for...in,就是Python中迭代器的语法糖。好了,现在你可能开始在想这个for做了什么事了,先把这个疑问放在心里,我们先一步步来解析上面的几个关键字。

Iterable 可迭代

先来看个反面教材,如果我们用for...in语法糖去遍历一个int会怎样???

intVal = 1024
for _ in intVal:
    pass

>>>TypeError: 'int' object is not iterable

从上面的错误可以看到,整数类型的对象不是可迭代的,也就是说for..in只适用于iterable对象,那么什么类型的对象才是iterable(可迭代)呢。

在Python中,实现了_iter_函数的类型都是可迭代的,例如list,tuple,dict等

可以用dir函数查看一下是否存在协议函数__iter__

print '__iter__' in dir(dict)
print '__iter__' in dir(list)
print '__iter__' in dir(tuple)

>>>True                                                                                                                                                                                                                                   
>>>True                                                                                                                                                                                                                                   
>>>True 

通过上面的方式我们可以判断一个对象是不是可迭代的,当然我们还有另外一种更接地气的方法。

l = [1]
from collections import Iterable
print isinstance(l, Iterable)  #注意这里只能用实例进行判断,而不能用list判断

iterator 迭代器

对于一个可迭代的对象,我们需要借助迭代器来对其进行迭代,那么我们怎么才能得到一个迭代器呢?

iter()方法

通过使用iter方法,我们可以得到一个迭代器,记住,要传入一个可迭代对象做为参数:

l = [1]
o = iter(l)
print type(o)
>>><type 'listiterator'>

从上面的代码可以看到,我们通过将一个可迭代对象传给iter方法得到了一个迭代器,那么有了这个迭代器之后,我们应该怎么迭代呢?

next()方法

调用迭代器next方法可以对元素进行遍历,但是next方法是不能无限使用的:

l = [1, 2, 3]
o = iter(l)
print o.next()
print o.next()
print o.next()
print o.next()

>>>1                                                                                                                                                                                                                                      
>>>2                                                                                                                                                                                                                                      
>>>3                                                                                                                                                                                                                                      
>>>Traceback (most recent call last):                                                                                                                                                                                                     
  File "e:\Microsoft VS Code\TestFiles\test.py", line 63, in <module>                                                                                                                                                                  
    print o.next()                                                                                                                                                                                                                     
StopIteration  

通过next方法我们可以一个个的遍历可迭代对象中的元素,当遍历结束的时候,会引发异常StopIteration


迭代器类

除了以上的方法,我们还可以构造一个类来进行迭代,这个类需要实现next__iter__方法,下面构造了一个斐波那契数列:

class FabIteratorClass(object):
    def __init__(self, max):
        self.m_Max = max
        self.m_Idx = 0
        self.m_a = 0
        self.m_b = 1

    def __iter__(self):
        return self

    def next(self):
        if self.m_Idx < self.m_Max:
            ret = self.m_b
            self.m_a, self.m_b = self.m_b, self.m_a + self.m_b
            self.m_Idx += 1
            return ret
        raise StopIteration()

for val in FabIteratorClass(3):
    print val

>>>1
>>>1
>>>2

所以,作为一个迭代器,他的特征如下:

  • 拥有__iter__方法,或者由iter方法返回
  • 拥有next方法
  • 会产生StopIteration异常

生成器

说到生成器,那么一定会说到一个关键字yield,只要一个函数里出现了这个关键字,我们就把这个函数称为生成器,生成器是一种内存友好的函数,例如平时用到的xrange函数,就是一个生成器,生成器不会把所有值预先生成,而是在需要时才生成,是一种Lazy Evaluation的做法。生成器也是迭代器的一种!

同样是斐波那契数列,我们用生成器处理一下:

def fab(max):
    idx = 0
    a = 0
    b = 1
    while idx < max:
        ret = b
        a, b = b, a + b
        idx += 1
        yield ret

c = fab(5)
print type(c)
for val in c:
    print val
>>><type 'generator'> 
>>>1                                                                                                                                                                                                                                      
>>>1                                                                                                                                                                                                                                      
>>>2                                                                                                                                                                                                                                      
>>>3                                                                                                                                                                                                                                      
>>>5 

总结:

  • 三者的继承关系是这样:generator--->Iterator--->Iterable
  • 迭代器类型需要实现__iter__next方法,生成器是一种特殊的迭代器,内部支持了生成器协议,不需要明确定义iter()和next()方法
  • 迭代器一定是可迭代对象,但是可迭代对象不一定是迭代器
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容