可迭代对象、迭代器、生成器的区别

本文深入解析了可迭代对象与迭代器的关系,阐述了如何定义及区分两者,重点介绍了生成器的概念、定义及其动态迭代特性。通过实例演示,展示了如何创建和使用MyList类和生成器myList来说明迭代过程。

一、三者的关系

二、可迭代对象与迭代器

  1. 可迭代对象包含迭代器;
  2. 若一个对象拥有__iter__方法,则是可迭代对象;若一个对象拥有next方法,则是迭代器
  3. 定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和next方法。
可能会发问:结论三与结论二是否有点矛盾?既然一个对象拥有next方法就是迭代器,那为什么迭代器必须同时时间__iter__与next方法?  原因就在于结论一,迭代器也是可迭代对象,因此迭代器必须也实现__iter__方法。

2.1、__iter__()与next()方法

__iter__():
    该方法返回的是当前对象的迭代器类的实例。因为可迭代对象与迭代器都要实现这个方法,因此有两种写法:
    写法一:用于可迭代对象类的写法,返回该可迭代对象的迭代器类的实例。
    写法二:用于迭代器类的写法,直接返回self(即自己本身),表示自身即是自己的迭代器。
next():
    该方法返回迭代的每一步,实现该方法时注意最后超出便捷要抛出StopIteration异常。

2.2、可迭代对象与迭代器定义

class MyList(object):                      # 定义可迭代对象类
    def __init__(self, num):
        self.data = num                    # 上边界

    def __iter__(self):
        return MyListIterator(self.data)  # 返回该可迭代对象的迭代器类的实例


class MyListIterator(object):          # 定义迭代器类,其是MyList可迭代对象的迭代器类
    def __init__(self, data):
        self.data = data               # 上边界
        self.now = 0                   # 当前迭代值,初始为0

    def __iter__(self):
        return self         # 返回该对象的迭代器类的实例;因为自己就是迭代器,所以返回self

    def __next__(self):     # 迭代器类必须实现的方法,python2中是next(),python3中是__next__()
        while self.now < self.data:
            self.now += 1
            return self.now - 1  # 返回当前迭代值
        raise StopIteration      # 超出上边界,抛出异常


my_list = MyList(5)             # 得到一个可迭代对象
print(type(my_list) )           # 返回该对象的类型
my_list_iter = iter(my_list)    # 得到该对象的迭代器实例,iter函数在下面会详细解释
print(type(my_list_iter))
for i in my_list:  # 迭代
    print(i)

print(type(iter(MyListIterator(1))))
# 结果
<class '__main__.MyList'>
<class '__main__.MyListIterator'>
0
1
2
3
4
<class '__main__.MyListIterator'>

注:iter()是直接调用该对象的__iter__(),并把__iter__()的返回结果作为自己的返回值

三、生成器

3.1、生成器概念

生成器 是种特殊的迭代器,生成器自动实现了“迭代器协议”(即__iter__与next方法),不需要再手动实现两方法。
生成器在迭代的过程中可以改变当前迭代值,而修改普通迭代器的当前迭代值往往会发生异常,影响程序的执行。

3.2、生成器定义

 
def myList(num):              # 定义生成器
    now = 0                   # 当前迭代值,初始为0
    while now < num:
        val = (yield now)     # 返回当前迭代值,并接受可能的send发送值;yield在下面会解释
        now = now + 1 if val is None else val  # val为None,迭代值自增1,否则重新设定当前迭代值为val


my_list = myList(5)            # 得到一个生成器对象
print(my_list.__next__())      # 返回当前迭代值
print(my_list.__next__())
my_list.send(3)                # 重新设定当前的迭代值
print(my_list.__next__())

print(dir(my_list))            # 返回该对象所拥有的方法名,可以看到__iter__与next在其中
# 结果
0
1
4
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
注:具有yield关键字的函数都是生成器,yield可以理解为return,返回后面的值给调用者。不同的是return返回后函数会释放,而生成器不会,在直接调用next()方法或用for语句进行下一次迭代时,生成器会从yield下一句开始执行,直至遇到下一个yield。 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值