zoukankan      html  css  js  c++  java
  • 迭代器、可迭代对象、for循环range本质

    迭代器

    迭代器的定义

    1/ 当一个类中 定义了 __iter__ 和 __next__ 两个方法
    2/ __iter__ 方法需要返回对象本身,也就是 self
    3/ __next__ 方法,返回下一个数据,如果没有数据了,需要抛出一个 StopIteration 的异常
    

    定义一个迭代器

    class It():
        def __init__(self) -> None:
            self.count = 0
    
        def __iter__(self):
            return self
        
        def __next__(self):
            self.count +=1
            if self.count == 5:
                raise StopIteration()
            return self.count
    

    这个类It 就是一个迭代器,而这个类的实例就是一个迭代器对象

    obj = It() # obj就是一个迭代器对象
    
    print(obj.__next__())
    print(obj.__next__())
    print(obj.__next__())
    print(obj.__next__())
    print(obj.__next__()) 
    输出:
    1
    2
    3
    4
    第五个print 报错 StopIteration()
    
    obj = It()
    print(next(obj))
    print(next(obj))
    print(next(obj))
    print(next(obj))
    print(next(obj))
    同上
    

    for 循环本质

    obj = It()
    
    for item in obj:
        print(item)
    输出:
    	1  2  3  4
    
    # 1/ for循环会去 执行迭代器对象obj的__iter__方法 并获取返回值【迭代器对象】
    # 2/ 一直不停的调用 next(对象) 并赋值给 item
    

    思考一个问题

    #修改代码为:
    for item in obj:
        print(next(obj))
        print(item)
    #输出 什么?
    

    分析:

    输出的结果为:
    2	1	4	3
    
    1/ for循环先执行obj的__iter__方法  返回的是obj 的self本身
    2/ 然后调用next(obj) 获取返回值 1  赋值给item
    3/ print(next(obj)) 这里再执行了一次 next(obj) 所以输出 2
    4/ 再来输出item  所以输出刚赋值的 1
    5/ 再调用next(obj) 获取返回值 3 赋值给item
    6/ print(next(obj)) 这里再执行了一次 next(obj) 所以输出 4
    7/ 输出刚赋值的item 所以输出 3
    8/ 再次尝试调用next(obj)赋值给 item  这时候5 已经触发了StopIteration终止循环
    所以输出的是 2 1 4 3
    

    生成器

    生成器本质上是一种特殊的迭代器

    def func():
        yeild 'aa'
        yeild 'bb'
    
    # 这里底层是用 generator 生成器类创建的一个对象,生成器内部也声明了 __iter__ __next__
    obj = func()
    
    print(type(obj)) # <class 'generator'>
    
    print(obj.__next__())  #aa
    print(next(obj)) #bb
    print(next(obj)) # 抛出StopIteration异常
    
    

    可迭代对象

    注意区分概念:
    1/ 迭代器对象: 由迭代器 实例化出来的对象 为迭代器对象
    2/ 可迭代对象: 如果一个类 有__iter__方法,且返回了一个 迭代器对象,那么这个类实例化出来的对象就为  可迭代对象
    

    举例:

    # 这是一个迭代器,实现了 __iter__ 和 __next__ 两个方法,并且iter返回本身
    class It():
        def __init__(self) -> None:
            self.count = 0
    
        def __iter__(self):
            return self
        
        def __next__(self):
            self.count +=1
            if self.count == 5:
                raise StopIteration()
            return self.count
    obj1 = It() ## 这个obj就是一个 迭代器对象
    
    #这个类 并不是迭代器,因为都没有__next__方法,但是这个类有__iter__方法,并且返回的是一个 迭代器对象【It 为迭代器,实例化是迭代器对象】
    class Demo:
        def __iter__(self):
            return It()
    demo = Demo()  ## 这个demo就是一个  可迭代对象
    
    for i in demo:
        print(i)
    
    # 同理,生成器是一个特殊的迭代器,所以生成器对象也是一个迭代器对象
    def func():
        yeild 1
        yeild 2
    class Demo2:
        def __iter__(self):
            return func()
    
    for i in demo2:
        print(i)
    
    
    class T:
        def __iter__(self):
            yield 1
            yield 'xx'
            yield 'haha'
    
    
    for i in T():
        print(i)
    
    

    理解练习

    for i in range(10):
        print(i)
    #这个 range(10)返回的一定是一个 可迭代对象
    
    v1 = range(10)
    print(dir(v1))
    # 返回的dir 发现只有__iter__, 并没有__next__,所以range()返回的只是一个可迭代对象,并不是迭代器对象
    
    #测试一下
    next(v1)  # 会报错  'range' object is not an iterator 说明不是一个迭代器对象
    
    v2 = v1.__iter__() # 可迭代对象的iter方法返回的是一个迭代器对象
    print(dir(v2))  #这里就可以看到有__iter__  有 __next__ 方法了
    
    print(v2,type(v2))# <range_iterator object at 0x7f5eac2ae960> <class 'range_iterator'>
    
    v2.__next__()
    next(v2)  执行就成功了
    

    需求:

    自定义一个range,要求是一个闭区间,比如原来的range(5) 只有 0 1 2 3 4,这里需要输出 0 1 2 3 4 5

    class MyIterRange():
    
        def __init__(self,min,max):
            self.min = min
            self.max = max
            self.strat = 0
    
        def __iter__(self):
            return self
        
        def __next__(self):
            self.min = self.min+self.strat
            self.strat = 1
            if self.min > self.max:
                raise StopIteration()
            return self.min
    
    class MyRange():
        def __init__(self,min,max):
            self.min = min
            self.max = max
        def __iter__(self):
            return MyIterRange(self.min,self.max)
    
    # 用可迭代对象
    for i in MyRange(1,9):
        print(i)
    
    # 直接用迭代器对象,迭代器对象一定是个可迭代对象
    for i in MyIterRange(-4,1):
        print(i)
    
    

    或者用更简单的方法:

    class MyYieldRange():
        
        def __init__(self,min,max):
            self.min = min
            self.max = max
        
        def __iter__(self):
            while self.min <= self.max:
                yield self.min
                self.min+=1
    
    
    for i in MyYieldRange(-1,8):
        print(i)
    

    结论

    • 迭代器 实例化 生成 迭代器对象

    • 生成器是一个特殊的迭代器,实例化出来的也是一个迭代器对象

    • 可迭代对象 不一定是 迭代器对象 ,但是迭代器对象一定是可迭代对象

    • for 循环本质是先去调用可迭代对象的__iter__方法,获取返回的迭代器对象,然后不停的调用迭代器对象的__next__方法 直到StopIteration()

  • 相关阅读:
    前端-浅谈Flex布局
    css-渐变简约的登录设计
    小程序-小程序后台原生图片识别
    小程序-云数据库实现好看的上传文件动态
    小程序-利用云开发操作云数据库实现点赞评论案例
    小程序-云存储实现对文件的上传下载
    小程序-浅谈云函数获取数据和云数据库api获取数据的区别
    小程序-简易加法教你如何使用云函数
    小程序-云数据库的add,get,remove,update
    小程序-你不得不知的Promise封装请求
  • 原文地址:https://www.cnblogs.com/alantammm/p/11858298.html
Copyright © 2011-2022 走看看