python知识——可迭代对象(Iterable)与迭代器(Iterator)以及生成器(Generator)

初识迭代器与可迭代对象 

直接可以作用于 for 循环的数据类型有以下几种:
   •  集合数据类型:
        list、tuple、dict、set、str (只是可迭代对象,不是迭代器)
   •  Generator:(既是可迭代对象,又是迭代器)
        带 yield 的generator function
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

        可以通过isinstance() 判断一个对象是否是可迭代对象Iterable以及是否是迭代器Iterator,如下示例1所示:

# 迭代器(Iterator)与可迭代对象(Iterable)
from collections import Iterable,Iterator
# isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
print(isinstance('abc', Iterable)) # True ‘’<class 'str'>
print(isinstance([], Iterable)) # True []表示列表
print(isinstance({}, Iterable)) # True <class 'dict'>
print(isinstance((), Iterable)) # True ()表示元组
print(isinstance([], Iterator)) # False
print(isinstance({}, Iterator)) # False
print(isinstance((), Iterator)) # False
m = set('runoob') # 创建一个集合:{'b', 'n', 'o', 'r', 'u'} 集合是一个可迭代对象(Iterable),但集合不是迭代器(Iterator)
print(isinstance(m, Iterable)) # True
print(isinstance(m, Iterator)) # False

        运行上述代码,我们可以得知,list、set、dict、 tuple、str 五种数据类型都是可迭代对象(Iterable),但都不是迭代器(Iterator)。

生成器

        在 Python 中,使用了 yield 关键字的函数被称为生成器(generator)。
        yield
 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。
        跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
        当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。
        调用一个生成器函数,返回的是一个迭代器对象。下面是一个简单的示例,展示了生成器函数的使用:(示例2)

# 生成器
def countdown(n):
    while n > 0:
        yield n
        n -= 1

# 创建生成器对象
generator = countdown(5)

# 通过迭代生成器获取值
print(next(generator))  # 输出: 5
print(next(generator))  # 输出: 4
print(next(generator))  # 输出: 3

# 使用 for 循环迭代生成器
for value in generator:
    print(value)  # 输出: 2 1

        以上实例中,countdown 函数是一个生成器函数。它使用 yield 语句逐步产生从 n 到 1 的倒数数字。在每次调用 yield 语句时,函数会返回当前的倒数值,并在下一次调用时从上次暂停的地方继续执行。
        通过创建生成器对象并使用 next() 函数或 for 循环迭代生成器,我们可以逐步获取生成器函数产生的值。在这个例子中,我们首先使用 next() 函数获取前三个倒数值,然后通过 for 循环获取剩下的两个倒数值。
        生成器函数的优势是它们可以按需生成值,避免一次性生成大量数据并占用大量内存。此外,生成器还可以与其他迭代工具(如for循环)无缝配合使用,提供简洁和高效的迭代方式。
        生成器不但可以用for循环,还可以被next()函数不断获取下一个值,直到最后抛出StopIteration错误,如下示例3所示。

# 生成器
def countdown(n):
    while n > 0:
        yield n
        n -= 1

# 创建生成器对象
generator = countdown(5)

# 通过迭代生成器获取值
print(next(generator))  # 输出: 5
print(next(generator))  # 输出: 4
print(next(generator))  # 输出: 3

# 使用 for 循环迭代生成器
for value in generator:
    print(value)  # 输出: 2 1
print(next(generator)) # 报错StopIteration

        示例3的代码在示例2 的基础之后添加了一句 print(next(generator)),执行该句代码,程序会抛出StopIteration错误。这是因为在执行该句代码之前迭代器中的内容已经被迭代完,若再次进行迭代,则会报错StopIteration。

        我们来看看生成器对象的类型,如下示例4所示:

from collections import Iterable,Iterator
# 生成器
def countdown(n):
    while n > 0:
        yield n
        n -= 1

# 创建生成器对象
generator = countdown(5)

print(isinstance(generator, Iterable)) # True
print(isinstance(generator, Iterator)) # True

        执行示例4所述代码,我们发现,生成器对象不仅仅是可迭代对象(Iterable),同时也是迭代器(Iterator)。 

迭代器 

        可以被next()函数不断返回下一个值的对象称为迭代器Iterator对象。迭代器都是Iterable对象,但是Iterable对象不一定是迭代器Iterator,如 list、dict、str、set、tuple。

a=[1, 2, 3]
x = next(a) 
print(x)# TypeError: 'list' object is not an iterator

可迭代对象 (Iterable) 变为迭代器 (Iterator) 

        把list、dict、str、tuple、set 等Iterable变成Iterator,可以使用iter()函数,如下示例5所示:

# iter()函数以及next()函数
a=[1, 2, 3] # a是可迭代对象,但不是迭代器对象
it = iter(a) #创建迭代器对象
x = next(it)
print(x) # 1
y = next(it)
print(y) # 2
z = next(it)
print(z) # 3
m = next(it)
print(m) # 报错 StopIteration

        我们为了避免报 StopIteration ,一般考虑如下改动,如下示例6所示:

扫描二维码关注公众号,回复: 16835445 查看本文章
# 首先获得Iterator对象:
it = iter([1, 2, 3])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
        print(x) # 1 2 3
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

这样改动之后,程序就不会因为StopIteration而报错了。

为什么list、dict、tuple、str、set等数据类型不是迭代器Iterator呢?

        Iterator对象表示的是一个数据流,可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出的StopIteration错误。这个数据流可以看作是一个有序序列,但是却不能提前知道序列的长度,只能不断通过next()函数来实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时才会进行计算。
        Iterator甚至可以表示一个无限大的数据流,而list、tuple等对象是永远不可能存储无限大的数据的,例如全体自然数。

迭代器 (Iterator) 和可迭代对象 (Iterable) 的区别

(1)迭代器一定是可迭代对象,但可迭代对象不一定是迭代器
(2)只有迭代器对象才能用next方法,也可以使用for循环;可迭代对象可以用for循环,但不能使用next方法
(3)一般可以用iter函数将可迭代对象转变为迭代器对象
(4)可迭代对象会直接将传入对象所有内容读取到内存中,而迭代器是一个个读取,只在需要的时候产生数据
 

猜你喜欢

转载自blog.csdn.net/m0_48241022/article/details/132869224