Python迭代与生成器

1、迭代

_iter_ 对象方法 可迭代对象,返回迭代器
__next_ 对象方法 迭代器对象,返回迭代中每一步的运算
iter(object) 内置函数 得到object的迭代器
next(object) 内置函数 得到迭代器的下一步迭代结果

1.1可迭代对象(Iterable)

如果一个对象实现了__iter__方法,那么这个对象就是可迭代对象

from collections.abc import Iterable, Iterator

class Color(object):

    def __init__(self):
        self.colors = ['red', 'white', 'black', 'green']

    # 仅仅是实现了__iter__ 方法,在方法内部什么都不做
    def __iter__(self):
        pass

color_object = Color()
# 判断是否为可迭代对象
print(isinstance(color_object, Iterable))       # True
# 判断是否为迭代器
print(isinstance(color_object, Iterator))       # False

可迭代对象未必是迭代器,只是实现了_iter_方法,但是可迭代对象可以被for遍历,那是因为

for的工作原理:
    1、使用iter获得可迭代对象的迭代器
    2、反复对迭代器使用next方法
    3、捕获StopIteration异常,退出循环

即for会使用iter去获得该可迭代对象的迭代器执行next方法遍历。

1.2迭代器

如果一个对象同时实现了__iter__方法和__next__方法,它就是迭代器

迭代器一定是可迭代对象,因为迭代器要求必须同时实现__iter__方法和__next__方法, 而一旦实现了__iter__方法就必然是一个可迭代对象。但是反过来则不成立,可迭代对象可以不是迭代器。

from collections.abc import Iterable, Iterator


class Color(object):

    def __init__(self):
        self.colors = ['red', 'white', 'black', 'green']

    # 仅仅是实现了__iter__ 方法,在方法内部什么都不做
    def __iter__(self):
        pass

    def __next__(self):
        pass

color_object = Color()
# 判断是否为可迭代对象
print(isinstance(color_object, Iterable))       # True
# 判断是否为迭代器
print(isinstance(color_object, Iterator))       # True

1.3迭代器工作原理

内置函数iter获得迭代器

iter函数的作用是从可迭代对象那里获得一个迭代器

from collections.abc import Iterator

lst_iter = iter([1, 2, 3])
print(isinstance(lst_iter, Iterator))       # Truefrom collections.abc import Iterator

lst_iter = iter([1, 2, 3])
print(isinstance(lst_iter, Iterator))       # True

使用内置函数next遍历迭代器

内置函数next的功能是从迭代器那里返回下一个值

from collections.abc import Iterator

lst_iter = iter([1, 2, 3])
print(next(lst_iter))       # 1
print(next(lst_iter))       # 2
print(next(lst_iter))       # 3
print(next(lst_iter))       # StopIteration

前3次调用next函数都能正常工作,第4次会抛出StopIteration异常,迭代器里已经没有下一个值了。

现在,让我们来做一个总结,遍历迭代器需要使用next方法,每调用一次next方法,就会返回一个值,没有值可以返回时,就会引发StopIteration异常。

为什么迭代器不能重复使用

iter函数每次会获得一个新的迭代器。

from collections.abc import Iterator

lst_iter = iter([1, 2, 3])
print(next(lst_iter))       # 1
print(next(lst_iter))       # 2  到了这一步,你想从头开始遍历,那么重新获得一个迭代器使用

lst_iter_2 = iter([1, 2, 3])
print(next(lst_iter_2))     # 1
print(next(lst_iter_2))     # 2
print(next(lst_iter_2))     # 3

1.4 自定义可迭代对象和迭代器

实现__iter__方法和___next___方法

如果可迭代对象实现了iter__方法,那么内置函数iter会调用对象的__iter__方法方法返回一个迭代器,由于Color类实现了__next__方法,因此Color的实例也是迭代器,在__iter__方法里返回self即可。

我们使用内置函数next对迭代器进行遍历,在这个过程中,是在调用迭代器的__next__方法, 内置函数的作用是返回迭代器的下一个值,这个功能的实现,我们需要放在__next__方法中。

class Color(object):

    def __init__(self):
        self.index = -1
        self.colors = ['red', 'white', 'black', 'green']

    def __iter__(self):
        self.index = -1
        return self

    def __next__(self):
        self.index += 1
        if self.index >= len(self.colors):
            raise StopIteration

        return self.colors[self.index]

color_object = Color()
for color in color_object:
    print(color)

2、生成器

⽣成器也是⼀种迭代器,但是你只能对其迭代⼀次。这是因为他们并没有把所有的值存在 内存中,⽽是在运⾏时⽣成值。

在待遍历列表占用空间非常大时候,或者用到的遍历项目并不多时候,使用迭代的方式需要将整个迭代变量放入内存中,就会非常占用资源和不合适。生成器据前面的元素推断后面的元素,一边循环一边计算的机制叫generator。generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

def intNum():
    print("开始执行")
    for i in range(5):
        yield i
        print("继续执行")
num = intNum()

和return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。不仅如此,即便调用生成器函数,Python 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)。

要想使生成器函数得以执行,或者想使执行完 yield 语句立即暂停的程序得以继续执行,有以下 2 种方式:

  1. 通过生成器(上面程序中的 num)调用 next() 内置函数或者 next() 方法;
  2. 通过 for 循环遍历生成器。
#调用 next() 内置函数
print(next(num))
#调用 __next__() 方法
print(num.__next__())
#通过for循环遍历生成器
for i in num:
    print(i)
posted @ 2023-03-09 21:21  饮一杯天上水  阅读(64)  评论(0)    收藏  举报