欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python中 迭代( iteration )、迭代对象( iterable )、迭代器( iterator)、生成器(generator) 的关系详细讲解

程序员文章站 2024-02-12 12:57:46
...

(1). 如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代

        只要是可迭代对象,无论有无下标,都可以迭代。使用for循环时,只要作用于一个可迭代对象,for循环就可以正常运行,而不太关心该对象究竟是list还是其他数据类型。

test1 = {'key1':2, 'key2':3, 'key3':4}
for key,value in test1.items():             # 遍历可迭代对象
    print("key:" + key)
    print("value:" + str(value))

(2). 判断一个对象是可迭代对象

       使用dir()函数查看对象的属性列表,如果只有__iter__()函数则是可迭代的,如果__iter__()和__next__()函数都有则是迭代器 或者 使用isinstance() 函数来判断一个对象是否是一个已知的类型。

test1 = {'key1':2, 'key2':3, 'key3':4}

kv1 = test1.items()
from collections import Iterable, Iterator
print(isinstance(kv1, Iterable))  # 判断是不是可迭代对象
print(isinstance(kv1, Iterator))  # 判断是不是迭代器

(3). 生成器( generator )

        如果列表元素可以按照某种算法推算出来,可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器

      ① 只要把一个列表生成式的[ ]改成(),就创建了一个generator。

         generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

L = [x*x for x in range(10)]
print(L)   # 输出结果:[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

g = (x*x for x in range(10))
print(g)   # 输出结果:<generator object <genexpr> at 0x00000180836FC1A8>
print(next(g))  # 输出结果:0

         如果要输出生成器所有的元素,当生成器的元素比较多时候,不断的调用next()函数就太麻烦了。可以使用for循环,因为generator也是可迭代对象。创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

g = (x*x for x in range(10))
for i in g:
    print(i, end=" ")
# 输出结果:0 1 4 9 16 25 36 49 64 81

     ② 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

           最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。在执行过程中,遇到yield就中断,下次又继续执行。把函数改成generator后,基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代。

def fib(max):
    '''
    斐波拉契数列(Fibonacci),除第一个和第二个数外,
    任意一个数都可由前两个数相加得到。
    '''
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

for n in fib(6):
    print(n)

         用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value

g = fib(6)
while True:
    try:
        x = next(g)
        print('g:', x)
    except StopIteration as e:
        print('Generator return value:', e.value)
        break

输出结果:

g: 1

g: 1

g: 2

g: 3

g: 5

g: 8

Generator return value: done

(4). 迭代器

直接作用于for循环的对象统称为可迭代对象:Iterable

生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了,可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。其实生成器就是迭代器

把list、dict、str等Iterable变成Iterator可以使用iter()函数

from collections import Iterable, Iterator
print(isinstance(iter([]), Iterator))      # 列表
print(isinstance(iter('abc'), Iterator))   # 字符串
print(isinstance(iter((1,2)), Iterator))   # 元组
print(isinstance(iter({1:2}), Iterator))   # 字典
print(isinstance(iter({1,2}), Iterator))   # 集合

可迭代对象不一定是迭代器,迭代器一定是可迭代对象。

迭代器:是一个可以记住遍历位置的对象,只能往前不会后退,有两个基本方法iter()、next()。字符串、列表或元组都可以用于创建迭代器。

Python的for循环本质上就是通过不断调用next()函数实现的。