python: 可迭代对象、迭代器、生成器

一、迭代

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/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值