用代码来解释可迭代性,迭代器,生成器的区别

一. 创造器(creator)

这是我自己造的一个名词,因为在python术语中,对只实现了__next__()方法的对象,好像没有任何名分,为了说明,我将只实现了__next__()方法的对象称为创造器(creator)。

class O_Next:
    def __init__(self):
        self.index = -1
        
    def __next__(self):
        self.index += 1
        return self.index

o_next = O_Next()

import collections
print(isinstance(o_next, collections.Iterable))
print(isinstance(o_next, collections.Iterator))


>>> False
>>> False

通过Python 的类型检查,可以看到,创造器即没有可迭代性,又不是python认可的迭代器,是一个无名英雄,还好我给它起了个名字来识别,创造器。

用标准函数 next(), 每调用一次创造器对象,将运行一次对象内部的__next__()方法;外部调用程序可决定需要调用多少次。

result = [next(o_next) for i in range(5)]
print(result)

result = [next(o_next) for i in range(5)]
print(result)

>>> [0, 1, 2, 3, 4]
>>> [5, 6, 7, 8, 9]

若用 while True 进行调用,对象将会被无限循环地调用下去;可在对象内部增加停止迭代的条件判断,通过触发 StopIteration异常,让调用程序捕获后,来终止迭代处理。

class O_Next2():
    def __init__(self):
        self.index = -1
        
    def __next__(self):
        if self.index > 5 - 1:
            raise StopIteration
        else:
            self.index += 1
            return self.index

o_next2 = O_Next2()
while True:
    try:
        print(next(o_next2))
    except StopIteration as e:
        break  


>>> 0
>>> 1
>>> 2
>>> 3
>>> 4
>>> 5

 

二. 可迭代对象(Iterable)

具有可迭代性的对象是内部只需要实现了 __iter__()方法的对象,该方法必须返回一个实现了 __next__()方法的创造器对象(官方认为必须返回的是迭代器对象,其实不然),否则无法被外部程序用for, list()等方法正常调用。比如: list(), set(), tuple()等,我们可以看看常见容器类型对象的可迭代性,是否为迭代器,及__next__()返回的迭代器对象

import collections

print(isinstance(list(), collections.Iterable), isinstance(list(), collections.Iterator), type(iter(list())))

print(isinstance(set(), collections.Iterable), isinstance(set(), collections.Iterator), type(iter(set())))

print(isinstance(dict(), collections.Iterable), isinstance(dict(), collections.Iterator), type(iter(dict())))

print(isinstance(tuple(), collections.Iterable), isinstance(tuple(), collections.Iterator), type(iter(tuple())))

>>> True False <class 'list_iterator'>
>>> True False <class 'set_iterator'>
>>> True False <class 'dict_keyiterator'>
>>> True False <class 'tuple_iterator'>

可见,常见容器对象具有可迭代性,但不是迭代器,它们有各自专用的迭代器。

接下来,我们自定义一个可迭代的对象,用自定义的创造器(不是迭代器)。

class O_Iter():
    def __iter__(self):
        return O_Next2() 
o_iter = O_Iter()

print(isinstance(o_iter, collections.Iterable), isinstance(o_iter, collections.Iterator),  type(iter(o_iter)))

>>> True False <class '__main__.O_Next2'>

用for, list(),调用可迭代对象,将返回一个创造器对象实例, 然后无限循环调用该创造器对象的 __next__()方法,并自动处理 StopIteration 异常以终止迭代处理。

x = [i for i in o_iter]
print(x)

print(list(o_iter))

>>> [0, 1, 2, 3, 4, 5]
>>> [0, 1, 2, 3, 4, 5]

 

三. 迭代器(Iterator)

迭代器(Iterator)是内部同时实现了__iter__()方法和__next__()方法的对象。

__next__()方法实现创造器逻辑,__iter__()方法提供可迭代性,并返回对象自身,或其它创造器。

在python的世界里,认为实现了__next__()方法的对象,基本都会同时实现__iter__()方法,返回自身,变成迭代器。因此,没有了只实现__next__()方法的创造器的位置。

class O_Iterator():
    def __init__(self):
        self.index = -1
        
    def __next__(self):
        if self.index > 5 - 1:
            raise StopIteration
        else:
            self.index += 1
            return self.index
        
    def __iter__(self):
        return O_Iterator()
    
o_iterator = O_Iterator()

print(isinstance(o_iterator, collections.Iterable), isinstance(o_iterator, collections.Iterator),  type(iter(o_iterator)))


>>> True True <class '__main__.O_Iterator'>

迭代器本身也具有可迭代性

x = [i for i in o_iterator]
print(x)

print(list(o_iterator))

>>> [0, 1, 2, 3, 4, 5]
>>> [0, 1, 2, 3, 4, 5]

 

四. 生成器(generator)

用更优雅简洁的方式来同时实现__iter__(), __next__(), 并自动触发StopIteration 异常

1. 生成器函数

生成器函数的实例调用,具有可迭代性,而且是迭代器

import collections

def o_generator(n):
    index = 0
    
    while index < n:
        yield index
        index += 1

print(isinstance(o_generator(5), collections.Iterable), isinstance(o_generator(5), collections.Iterator),  type(iter(o_generator(5))))

>>> True True <class 'generator'>
x = [i for i in o_generator(5)]
print(x)

print(list(o_generator(5)))

>>> [0, 1, 2, 3, 4]
>>> [0, 1, 2, 3, 4]

2. 生成器表达式

列表生成器不加方括[ ],而是用圆括号( ),就变成了一个生成器对象(generator)

o_gen2 = (i*i for i in range(5))

print(isinstance(o_gen2, collections.Iterable), isinstance(o_gen2, collections.Iterator),  type(iter(o_gen2)))

>>> True True <class 'generator'>

可迭代处理

o_gen2 = (i*i for i in range(5))

x = [i for i in o_gen2]
print(x)

print(list(o_gen2))

>>> [0, 1, 4, 9, 16]
>>> []

为什么第2次 print()输出的为空???

对同一个迭代器对象实例,全部遍历完后,就结束了,不会自己从头再来。 仔细分析观察其他的代码,每次都是重新生成了一个迭代器对象实例(创造器对象实例),初始化后,从头开始遍历的。我们可以把生成器函数的例子改写一下看看,结果将一样。

def o_generator(n):
    index = 0
    
    while index < n:
        yield index
        index += 1


o_gen = o_generator(5)

x = [i for i in o_gen]
print(x)

print(list(o_gen))


>>> [0, 1, 2, 3, 4]
>>> []

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值