天天看点

python: 可迭代对象、迭代器、生成器一、迭代二、可迭代对象(iterable)三、迭代器四、迭代原理五、生成器参考资料

一、迭代

1、定义

迭代是指通过for循环遍历对象每一个元素的过程。

二、可迭代对象(iterable)

1、定义

可迭代对象是定义了

__iter__()

方法或

__getitem__()

方法的类对象。

2、

__iter__()

from collections import abc


class MyIterable:
    def __iter__(self):
        pass


my_iterable = MyIterable()
           

3、

__getitem__()

from collections import abc


class MyIterable:
    def __getitem__(self, item):
        pass


my_iterable = MyIterable()
           

定义了

__iter__()

__getitem__()

方法后,对象就可以使用for循环遍历了。当然,上面只是一个简单的示例,什么功能都没有,实际情况一般基于Python的内置数据类型(int, list, string…)去写。在引入迭代器之后,

__iter__()

的功能一般是返回一个迭代器。

4、说明

很多文章喜欢拿

collections.abc.Iterable

对象和一个类对象比较,然后判断这个类对象是否是可迭代对象。如:

from collections import abc
class MyIterable:
    def __getitem__(self, item):
        pass
my_iterable = MyIterable()
print(isinstance(my_iterable, abc.Iterable))
           

其实这是不完全正确的。因为根据Python文档, Iterable 只实现了

__iter__()

方法,所以一个对象如果实现 了

__getitem__()

方法,但是没有实现

__iter__()

方法,用这种方式判断,该对象就会被判定为不是可迭代对象,这是错误的。只要实现这两个方法中的任何一个,都是可迭代对象,应该使用**iter()**方法。

三、迭代器

1、定义

实现了迭代器协议(

__iter__()

,

__next__()

)的类对象称为迭代器。迭代器是在Python 2.2引入的,因为迭代器实现了

__iter__()

方法,所以迭代器也属于可迭代对象。

2、

__iter__()

返回对象本身。

3、

__next__()

返回对象的下一个元素,如果没有下一个元素则抛出

StopIteration

异常。

# 模仿range()迭代器自定义一个迭代器
class MyRangeIterator:
    def __init__(self, num):
        self.num = num
        self.index = 0  # 设置第一个元素

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < self.num:
            val = self.index
            self.index += 1  # 为了每次返回下一个元素,所以每次+1
            return val
        else:
            raise StopIteration()  # 如果没有元素了则抛出StopIteration


mri = MyRangeIterator(5)
print([i for i in mri])  # [0, 1, 2, 3, 4]
print([i for i in mri])  # []
           

4、典型的可迭代对象与迭代器

典型的可迭代对象的

__iter__()

方法返一个新的迭代器实例,而迭代器的

__iter__()

方法返回迭代器本身。

# 可迭代对象
class MyRange:
    def __init__(self, num):
        self.num = num

    def __iter__(self):
        return MyRangeIterator(self.num)


# 迭代器
class MyRangeIterator:
    def __init__(self, num):
        self.num = num
        self.index = 0  # 设置第一个元素

    def __iter__(self):
        return self

    def __next__(self):
        if self.index < self.num:
            val = self.index
            self.index += 1  # 为了每次返回下一个元素,所以每次+1
            return val
        else:
            raise StopIteration()  # 如果没有元素了则抛出StopIteration


mr = MyRange(5)
print([i for i in mr])  # [0, 1, 2, 3, 4]
print([i for i in mr])  # [0, 1, 2, 3, 4]

           

四、迭代原理

解释器需要迭代对象 x 时,每迭代一次:

(1)执行 iter(x)。

(2)检查对象是否实现了

__iter__

方法,如果实现了就调用它,获取到一个迭代器iterator。

(3)获取到迭代器之后,执行

next(iterator)

(4)然后执行

iterator.__next__()

获取元素。

(5)如果没有元素了就抛出

StopIteration

五、生成器

1、定义

根据Python术语表,有:

(1)generator

包含

yield

表达式的函数或者生成器叫做生成器。生成器本质上是一个函数,也叫生成器函数(generator function)。

示例:

def gen_123():
    yield 123


print(gen_123)  #<function gen_123 at 0x00000269E04D6558>,生成器本质上是一个函数
           

(2)generator iterator

生成器生成的对象(generator object,简称生成器对象)称为“generator iterator”。为什么这样命名呢?因为生成器对象也是一个迭代器。

示例:

from collections import abc


def gen_123():
    yield 123


print(gen_123)  # <function gen_123 at 0x00000269E04D6558>

g = gen_123()
print(g)  # <generator object gen_123 at 0x00000269E0446C48>,生成器对象
print(isinstance(g, abc.Iterator))  # True,生成器生成的对象也是一个迭代器
           

下面是个人理解(不一定正确):

a.

generator iterator

这个名称有点“怪”,咋一看,你不知道它所表达的意思到底是生成器还是迭代器,还有点拗口,可能官方想表达的是

生成器生成的迭代器

b.有人喜欢把生成器称为“特殊的迭代器”,其实这是不对的,生成器本质是函数,而迭代器本质是类对象。生成器生成的对象才是迭代器。

2、yield

关于yield的实现原理,可以参考这篇文章Python yield。本文只说yield的用法。

yield表达式 的语法如下:

yield_atom       ::=  "(" yield_expression ")"
yield_expression ::=  "yield" [expression_list | "from" expression]
           

yield关键字的功能:

(1)返回给调用者一个值,并挂起当前状态。

(2)当执行next(

generator iterator

),从离开的地方继续。

3、示例

class MyRange:
    def __init__(self, num):
        self.num = num
        self.index = 0

    def __iter__(self):
        return self.my_range_generator()

    def my_range_generator(self):
        while self.index < self.num:
            yield self.index
            self.index += 1


my_range = MyRange(5)
for i in my_range:
    print(i, end=' ')  # 0 1 2 3 4 
           

4、生成器表达式

生成器表达式的作用和生成器函数的作用也是一样的,生成一个

generator iterator

。所以也是一种生成器。

(1)语法

generator_expression ::=  "(" expression comp_for ")"
           

(2)示例

g = (x*y for x in range(10) for y in range(x, x+10))
           

参考资料

[1]PEP234, iterator: https://www.python.org/dev/peps/pep-0234/

[2]PEP255, Simple Generators: https://www.python.org/dev/peps/pep-0255/

[3]PEP342, Coroutines via Enhanced Generators:https://www.python.org/dev/peps/pep-0342/