彻底理解Python迭代器

 

如何理解迭代对象迭代器以及迭代协议:

 Iterable              Iterator

 

1、可迭代对象和迭代器

 可迭代的对象有个 __iter__ 方法,每次都实例化一个新的迭代器;而迭代器要实现 __next__ 方法,返回单个元素,此外还要实现 __iter__ 方法,返回迭代器本身

 

可迭代的对象一定不能是自身的迭代器。也就是说,可迭代的对象必须实现

__iter__ 方法,但不能实现 __next__ 方法

 

 

 

2、迭代器:

迭代器是这样的对象:实现了无参数的 __next__ 方法,返回序列中的下一个元素;如果没有元素了,那么抛出 StopIteration 异常。 Python 中的迭代器还实现了__iter__ 方法,因此迭代器可以迭代。

 

 

 

 

3、序列可以迭代原因

 

    iter 函数:解释器需要迭代对象X时,会自动调用iter(X)

 

4 内置iter函数作用

 

1、检查对象是否实现了__iter__方法,如果实现就调用,获取一个迭代器。

2、如果没有实现__iter__,但是有__getitem__方法,Python会创建一个迭代器,尝试按顺序从索引0开始获取元素。

3、如果尝试失败抛出TypeError异常

 

4、理解迭代协议

Python 迭代协议要求一个 __iter__() 方法返回一个特殊的迭代器,这个迭代器实现了 __next__() 方法,并通过 StopIteration异常标识迭代完成。

 

 

Eg: 如下代码,按照迭代协议描述:

 

 

# -*- coding:utf -*-

import re

import reprlib

 

RE_WORD= re.compile('\w+')

 

 

class Sentence:

    def__init__(self, text):

        self.text= text

        self.words= RE_WORD.findall(text)

 

    def__repr__(self):

        return 'Sentence(%s)' %reprlib.repr(self.text)

 

    def__iter__(self):

        return SentenceIterator(self.words)

 

 

class SentenceIterator:

    def__init__(self, words):

        self.words= words

        self.index= 0

 

    def __next__(self):

        try:

            word = self.words[self.index]

        except IndexError:

            raise StopIteration()

        self.index+= 1

        return word

 

    def__iter__(self):

        return self

 

if __name__ == '__main__':

    s = Sentence('helloworld')

    it = iter(s)

    print(it) 

    print(next(it))

    print(next(it)) 

 

结果:

<__main__.SentenceIteratorobject at 0x03561F30>

hello

World

符合可迭代对象和迭代器的描述情况。

如果我们不按照这种协议的说明:__iter__ 函数不返回一个迭代器,使用别的函数返回迭代器情况会是什么。修改代码如下,并执行打印:

 

# -*- coding:utf -*-

import re

import reprlib

 

RE_WORD= re.compile('\w+')

 

 

class Sentence:

    def__init__(self, text):

        self.text= text

        self.words= RE_WORD.findall(text)

 

    def__repr__(self):

        return 'Sentence(%s)' %reprlib.repr(self.text)

 

    def__iter__(self):

        return iter(self.words)

 

    defshow_word(self):

        return SentenceIterator(self.words)

 

 

class SentenceIterator:

    def__init__(self, words):

        self.words= words

        self.index= 0

 

    def __next__(self):

        try:

            word = self.words[self.index]

        except IndexError:

            raise StopIteration()

        self.index+= 1

        return word

 

    def__iter__(self):

        return self

 

if __name__ == '__main__':

    s = Sentence('helloworld')

    print(s.show_word())

    print(next(s.show_word()))

    forword in s.show_word():

        print(word)

 

运行结果:

<__main__.SentenceIteratorobject at 0x03271250>

hello

hello

world

 

 

接着执行如下:

if __name__ == '__main__':

    s = Sentence('helloworld')

    it = iter(s)

    print(it)

    print(next(it))

    print(next(it))

 

运行结果:

hello

world

 

因为 __iter__ 函数返回值是个list 类型,所以使用iter()函数依旧可以生成一个list_iterator。原始数据可迭代,使用iter()函数可生成一个迭代器

如果原始数据不可迭代,调用iter就会报错:

>>> s = 14

>>> s

14

>>>iter(14)

Traceback (mostrecent call last):

  File "", line 1,in

    iter(14)

TypeError: 'int'object is not iterable

 

以上两种方式是为了理解迭代对象和迭代器,实时上这种写法过于繁琐,使用生成器来实现迭代器:

 

# -*- coding:utf -*-

import re

import reprlib

 

RE_WORD= re.compile('\w+')

 

 

class Sentence:

    def__init__(self, text):

        self.text= text

        self.words= RE_WORD.findall(text)

 

    def__repr__(self):

        return 'Sentence(%s)' %reprlib.repr(self.text)

 

    def__iter__(self):

        for i in self.words:

            yield i

 

 

if __name__ == '__main__':

    s = Sentence('helloworld')

    it = iter(s)

    print(it)

    print(next(it))

    print(next(it))

 

输出结果:

hello

world

 

使用生成器很大减少了繁琐的自己实现一个迭代器并且实现 __next__方法。

 

当然生成器除了使用: yield关键字以外还可以使用生成器表达式,类似于列表推导式。

# -*- coding:utf-8 -*-

 

def gen_():

    print('start')

    yield'a'

    print('continue')

    yield'b'

    print('end.')

 

res1 =[x*3 for x in gen_()]

print(res1)

res2 =(x*3 for x in gen_())

print(res2)

 

输出结果:

start

continue

end.

['aaa', 'bbb']

at 0x02B36540>

列表推导式直接打印出来了所有的结果,而生成器表达式并没有,生成器表达式可以使用next()函数来输出结果。

你可能感兴趣的:(彻底理解Python迭代器)