• Python中的迭代器


    迭代器:iterator
    可迭代对象:iterable

    迭代器

    在本文中,我们将学习迭代器是如何工作的,以及如何使用 __iter__()__next__() 方法构建自己的迭代器。

    迭代器(Iterator)是可以迭代的对象,在 Python 中无处不在。它们在 for 循环、推导式、生成器等中得到了优雅的实现,但却隐藏在显而易见的地方。

    Python 中的迭代器只是一个可以迭代的对象。一个每次仅仅返回一个元素的对象(有点像挤牙膏)。从技术上讲,Python 迭代器对象必须实现两个魔法方法:__iter__()__next__()方法,统称为迭代器协议(iterator protocol)。

    如果我们可以从一个对象中得到一个迭代器,那么这个对象就被称为可迭代对象(iterable)。Python 中的大多数内置数据结构(容器)都是可迭代对象,比如 list列表、 tuple元组、 str字符串等等。iter ()函数(反过来调用__iter__()方法)从它们中返回一个迭代器。

    遍历迭代器

    我们使用 next() 函数手动遍历迭代器的所有元素。当我们到达结尾时,如果没有更多的数据要返回,它将引发 StopIteration异常。

    示例:

    # 定义一个列表
    my_list = [4, 7, 0, 3]
    
    # 使用iter()返回一个迭代器对象
    my_iter = iter(my_list)
    
    # 使用next()方法依次遍历
    print(next(my_iter))  # 将打印 4
    print(next(my_iter))  # 将打印 7
    
    # next(obj) 和 obj.__next__()效果一样
    print(my_iter.__next__())  # 将打印 0
    print(my_iter.__next__())  # 将打印 3
    
    next(my_iter)  # 将会引起 StopIteration 异常
    

    输出结果:

    4
    7
    0
    3
    Traceback (most recent call last):
      File "<string>", line 24, in <module>
        next(my_iter)
    StopIteration
    

    一种更优雅的自动迭代方式是使用 for 循环。这样一来,我们可以遍历任何可以返回迭代器的对象,例如列表、字符串、文件等等。

    示例:

    # 定义一个列表
    my_list = [4, 7, 0, 3]
    
    # 使用for循环遍历
    for i in my_list:
        print(i)
    

    迭代器中的for循环

    正如我们在上面的例子中看到的,for循环能够自动遍历列表。实际上,for 循环可以遍历任何可迭代的对象。让我们仔细看看 for 循环是如何在 Python 中实现的。

    # 从可迭代对象中创建一个迭代器对象
    iter_obj = iter(iterable)
    
    # 开启无限循环
    while True:
        try:
            # 遍历元素
            element = next(iter_obj)
            # 对元素进行一些操作
            pass
        except StopIteration:
            # 如果引起StopIteration则终止循环
            break
    

    由此可见,for 循环在内部通过对可迭代对象(iterable)调用 iter()方法,来创建出一个迭代器(iterator)对象 iter_obj

    笑不活的是,这个 for循环实际上竟是一个无限 while循环......意不意外,惊不惊喜。

    自定义迭代器

    在 Python 中,从零开始构建迭代器很容易,我们只需要实现 __iter__()__next__() 方法。

    • __iter__()方法返回迭代器对象本身. 如果需要,可以执行一些初始化。

    • __next__()方法必须返回序列中的下一项。在到达结尾时,以及在随后的调用中,它必须引发StopIteration 异常。

    下面,我们展示一个例子,它将给出每次迭代中2的下一次幂。其中幂指数从零开始到用户设置的数字。

    class PowTwo:
        """2的迭代器指数类"""
    
        def __init__(self, max=0):
            self.max = max
    
        def __iter__(self):
            self.n = 0
            return self
    
        def __next__(self):
            if self.n <= self.max:
                result = 2 ** self.n
                self.n += 1
                return result
            else:
                raise StopIteration
    
    
    # 创建可迭代对象
    numbers = PowTwo(3)
    
    # 获得一个迭代器
    i = iter(numbers)
    
    # 获取下一个元素
    print(next(i))
    print(next(i))
    print(next(i))
    print(next(i))
    

    执行后,输出结果:

    1
    2
    4
    8
    

    我们还可以使用 for 循环迭代迭代器类。

    for i in PowTwo(5):
        print(i)
    

    执行后输出结果:

    1
    2
    4
    8
    16
    32
    

    无限迭代器

    迭代器对象中的项不必用尽。可以有无限迭代器(它永远不会结束)。在处理这样的迭代器时,我们必须小心。

    下面是演示无限迭代器的一个简单示例。

    内置函数 iter()还有一种用法是:

    iter(callable, sentinel) -> iterator
    

    也就是说,它在调用时可以接收两个参数 ,其中第一个参数必须是可调用对象(函数) ,第二个参数必须是哨兵。迭代器调用这个函数,直到返回的值等于哨兵。

    我们知道python中的 int()函数默认总是返回0。因此,将它作为 iter(int,1)传递将返回一个调用 int()的迭代器,直到返回的值等于1。这种情况从来没有发生,我们得到了一个无限迭代器。

    不仅如此,我们还可以构建自己的无限迭代器。

    class InfIter:
        """一个用来返回所有的奇数的无限迭代器类"""
    
        def __iter__(self):
            self.num = 1
            return self
    
        def __next__(self):
            num = self.num
            self.num += 2
            return num
    

    执行后输出结果:

    1
    3
    5
    ...
    

    其中...表示后续输出无穷无尽。

    因此,在遍历这些类型的无限迭代器时,要注意包含终止条件。

    其实,Python中还有一种更简单的创建迭代器的方法,就是使用生成器 generator

    ---END

  • 相关阅读:
    灌溉 最小生成树
    queue的应用uva540
    大数相加
    对于jquery实现原理的浅谈
    div+CSS实现页面的布局要点记录
    spring注解注入的学习
    jsp内置对象学习记录
    web应用的乱码解决
    新发现:排序算法时间复杂度只有O(3n),命名为"wgw"排序法
    java编写的Http协议的多线程下载器
  • 原文地址:https://www.cnblogs.com/amoyshmily/p/16047536.html
Copyright © 2020-2023  润新知