zoukankan      html  css  js  c++  java
  • 迭代器

    迭代器协议

    对象必须提供一个 next() 方法,执行该方法要么迭代下一项,要么就引起一个 StopIteration异常以终止迭代(只能往后不能往前)—— 迭代器协议

    协议是一种约定,可迭代对象实现了迭代器协议(for、sum、min、max 等使用迭代器协议访问对象)

    可迭代对象(iterable)

    实现了迭代器协议的对象,就是可迭代对象。如何实现迭代器协议:对象内部定义 __iter__() 方法。

    可作用于 for 循环的对象统称为可迭代对象,能作用于 for 循环的数据类型有以下几种:

    • 集合数据类型:liststrtupledicttuple
    • 生成器 generator:包括生成器函数和带 yield 关键字的生成器对象

    可以用 isinstance() 判断一个对象是否是可迭代对象:

    from collections import Iterable
    	
    isinstance([], Iterable)			# True
    isinstance('123', Iterable)			# True
    isinstance(123, Iterable)			#  False
    

    可迭代对象是可迭代的(即能被 for 循环),但不是迭代器,因为 next() 函数无法调用它们:

    next([1, 2, 3])
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-38-4a6488f07b8e> in <module>()
    ----> 1 next([1, 2, 3])
    
    TypeError: 'list' object is not an iterator		# list 对象不是一个迭代器
    

    但是可以用 iter() 函数将其转换为迭代器:

    l = [1, 2, 3]
    ret = iter(l)		# 转换为迭代器
    next(ret)			# 调用 next() 函数
    
    ------------------------
    1
    

    迭代器(iterator)

    可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator

    迭代器对象从集合第一个元素开始访问,直到所有元素被访问完才算结束,只能往前不能往后。

    使用isinstance()判断一个对象是否是Iterator对象:

    from collections import Iterator
    isinstance([], Iterator)        					# list 不是迭代器对象,False
    isinstance(iter([1, 2, 3]), Iterator)   			# 用 iter() 将 list 转换为迭代器,True
    isinstance((x for x in range(10)), Iterator)   		# 生成器是迭代器对象
    

    迭代器惰性机制

    迭代器表示的是一个数据流,可以调用 next() 函数不断返回下一个数据,直至没有数据抛出 StopIteration。可以说它是一个有序序列,但我们不知道序列长度,只能通过 next() 函数实现按需计算下一个数据,所有它是惰性的,只有在需要时才计算返回下一个数据。


    为什么要有迭代器

    对于有序序列类型,使用索引以及 while 循环也难遍历所有元素,但是对于无序序列类型(字典、集合)就会束手无策。


    for 循环机制

    for 循环是基于迭代器协议提供了一个统一的可遍历所有对象的方法,调用对象的 __iter__() 方法将其转换为一个迭代器,再调用 __next__() 不断取出序列中元素。相比较迭代器而已,for 循环还完成了 StopIteration 的异常工作。

    这样一来,只要是序列,都可以通过 for 循环遍历,不管是有序还是无序序列类型。


    优缺点

    优点:

    • 提供一种不依赖于索引的迭代方式
    • 惰性计算,节省内存(每次取值,才会加载)

    缺点:

    • 无法获取长度,next() 完毕才知道
    • 一次性,只能往前,不能往后

    自定义类为迭代器

    要想将自定义的类实现为一个迭代器,需要在类中实现 __iter__()__next__()方法:

    • __iter__() 方法:返回迭代器对象本身
    • __next__() 方法:返回容器中下一个元素,当超出边界时触发 StopIteration 异常终止迭代器
    class Foo(object):
        def __init__(self,step):
            self.step = step
            
        def __next__(self):
            if self.step == 0:
                raise StopIteration
            self.step -= 1
            return self.step
        
        def __iter__(self):
            return self
    f = Foo(6)
    for i in f:
        print(i)
    
    5
    4
    3
    2
    1
    0
    

    总结

    • 可以 for 循环的对象都是可迭代类型
    • 可以作用于 next() 函数的对象都是迭代器类型,它表示一个惰性计算的序列
    • listdictstr 等都是可迭代的,但不是迭代器类型,因为没有 next() 方法,可以用 iter() 函数将其转换为迭代器
    • Python 的 for 循环机制其实质是不断调用 next() 函数实现的,但是它超出边界不会触发 StopIteration
    • for 循环一次将所有数取出,迭代器一次只取一个
  • 相关阅读:
    Trapping Rain Water
    Construct Binary Tree from Preorder and Inorder Traversal
    Flatten Binary Tree to Linked List
    Permutations II
    Unique Paths II
    Path Sum II
    Unique Binary Search Trees II
    evdev module-----uinput.py
    evdev module-----events.py
    evdev module-----device.py
  • 原文地址:https://www.cnblogs.com/midworld/p/10471607.html
Copyright © 2011-2022 走看看