高级特性:迭代器

文章大部分参考来源:No-Coder's Blog

1. 可迭代对象

我们已经知道可以对list、tuple、str等类型的数据使用for...in...的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。

但是,是否所有的数据类型都可以放到for...in...的语句中,然后让for...in...每次从中取出一条数据供我们使用,即供我们迭代吗?

#!/usr/bin/env python2.7
# -*- coding=utf-8 -*-


for i in 100:
    print i

# >>> TypeError: 'int' object is not iterable
# int类型的对象是不可迭代的


class MyList(object):
    def __init__(self):
        self.names = []
    
    def add(self, value):
        self.names.append(value)


mylist = MyList()
mylist.add('1')
mylist.add('2')
mylist.add('3')


for i in mylist:
    print i

# >>> TypeError: 'MyList' object is not iterable
# MyList类型的对象是不可迭代的

 

2. 如何判断一个对象是否可迭代

"""
可以使用isinstance来判断对象是否为可迭代的
"""

from collections import Iterable

isinstance([], Iterable)
# True

isinstance({}, Iterable)
# True

isinstance('abc', Iterable)
# True

isinstance(mylist, Iterable)
# False

isinstance(100, Iterable)
# False

3. 可迭代对象的本质

“”“
让我们来看下能够被for...in循环取值的类型到底都有什么相同的特性?
使用dir发现list tuple dict 这些数据类型都有一个函数叫__iter__函数是不是实现了这个函数 我们对应创建的内容就是可迭代的
”“”

class MyList(object):
    def __init__(self):
        self.names = []
    
    def add(self, value):
        self.names.append(value)

    def __iter__(self):
        pass


mylist = MyList()
mylist.add('1')
mylist.add('2')
mylist.add('3')


for i in mylist:
    print i

# >>> TypeError: iter() returned non-iterator of type 'NoneType'
# MyList类型的对象iter函数返回的不是关于iterator的对象
# 那我们再去修改一下


class MyList(object):
    def __init__(self):
        self.names = []
    
    def add(self, value):
        self.names.append(value)

    def __iter__(self):
        return MyIterator(self)


class MyIterator(object):
        def __init__(self, mylist):
                self.mylist = mylist
                self.current = 0 

        def __next__(self):
                if self.current < len(self.mylist.container):
                        item = self.mylist.container[self.current]
                        self.current += 1
                        return item
                else:
                        raise StopIteration

mylist = MyList()
mylist.add(1)
mylist.add(2)   
mylist.add(3)
for i in mylist:
    print(i)

# 1 2 3 
# 成功我们先不管MyIterator是什么,我们目前关心的是只要对应的对象中实现了iter并且返回了对应的迭代器对象这个时候我们实现的对象就可以称之为可迭代的

4. iter()以及next()

li_iter = iter(li)
next(li_iter)
# 11
next(li_iter)
# 22
next(li_iter)
# 33
next(li_iter)
# 44
next(li_iter)
# 55
next(li_iter)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

"""
list、tuple等都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。iter()函数实际上就是调用了可迭代对象的__iter__方法。而__iter__方法则返回包含next函数的迭代器对象,然后我们使用迭代器对象的next方法不停的取出下一个值,直到raise为止
"""

5. 如何判断一个对象是否为迭代器

from collections import Iterator

isinstance([], Iterator)
# False

isinstance(iter([]), Iterator)
# True

isinstance(iter("abc"), Iterator)
# True

6. 迭代器iterator

"""
通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的__next__方法(Python3中是对象的__next__方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。
总结来说:一个实现了__iter__方法和__next__方法的对象,就是迭代器。
"""

class MyList(object):

        def __init__(self):
                self.container = []

        def add(self, item):
                self.container.append(item)

        def __iter__(self):
                """返回一个迭代器"""
                return MyIterator(self)


class MyIterator(object):
    
        def __init__(self, mylist):
                self.mylist = mylist
                self.current = 0 

        def __next__(self):
                if self.current < len(self.mylist.container):
                        item = self.mylist.container[self.current]
                        self.current += 1
                        return item
                else:
                        raise StopIteration

if __name__ == "__main__":
        mylist = MyList()
        mylist.add(1)
        mylist.add(2)   
        mylist.add(3)

        for i in mylist:
            print(i)

7. for.....in的本质

for item in items  循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器Iterator,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。

8. 迭代器简单的练习题

# 斐波那契实现

class Feb(object):
    def __init__(self,num):
        self.num = num
        self.index = 0
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def next(self):
        if self.index < self.num:
            v = self.a
            self.a, self.b = self.a + self.b, self.a
            self.index += 1
            return v

        else:
            raise StopIteration


if __name__ == '__main__':
    f = Feb(20)
    for i in f:
        print i
# 倒叙取值

class Reverse(object):


    def __init__(self,list):
        self.num = len(list)
        self.target = list

    def __iter__(self):
        return self

    def next(self):
        self.num -= 1
        if self.num >= 0:
            return self.target[self.num]
        else:
            raise StopIteration

if __name__ == '__main__':
    list  = [1, 2, 3, 4, 5, 6, 7, 8]
    r = Reverse(list)
    for i in r:
        print i

学习到这我们总结一下:

可迭代对象(实现了iter方法,iter方法返回迭代器对象)

迭代器对象(实现了iter以及next方法)

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值