zoukankan      html  css  js  c++  java
  • 迭代器,生成器,可迭代对象

    迭代器,生成器

    迭代器

    一个类,如果实现:

    1. 实现 __iter__(self) 方法,并返回自身 self
    2. 实现 __next__(self) 方法,返回迭代的值。

    举例:

    from collections.abc import Iterator,Iterable
    
    class it(object):
        def __init__(self, num):
            self.num = num
    
        def __iter__(self):
            return self
    
        def __next__(self):
            self.num += 1
            # 大于10,抛出异常
            if self.num > 10:
                raise StopIteration
            return self.num
    
    ge = it(1)
    print(isinstance(ge,Iterable))
    print(isinstance(ge,Iterator))
    

    可迭代对象

    实现了 __iter__(self), 返回一个迭代器,就是一个可迭代对象。

    iter() 可以将一个可迭代对象转变成一个迭代器。

    from collections.abc import Iterator,Iterable
    
    class it(object):
    
        def __iter__(self):
            return iter([1,2,3])
    
    ge = it(1)
    print(isinstance(ge,Iterable))
    print(isinstance(ge,Iterator))
    

    生成器

    使用 yield 关键字,可以实现生成器, 而且可以直接使用 next()

    class generator(object):
        def __init__(self, num):
            self.num = num
    
        def __iter__(self):
            while self.num < 10:
                yield self.num
                self.num += 1
    
    ge = generator(1)
    print(type(ge))
    print(isinstance(ge,Iterable))
    print(isinstance(ge,Iterator))
    

    当然,上面是一个生成器类,其实生成器跟 __iter__() 没啥太大关系,只要随便使用一个函数,使用 yield 关键字就行了:

    def generator():
        yield 1
        
    g = generator()
    print(g)
    

    生成器的 next(), send(), yield from

    next(generator) 很简单,就是不停的执行从当前代码,执行到下一个 yield 处,返回当前 yield 的数据

    send(msg) 可以给生成器发送数据,进行数据交互,然后执行到下一个 yield 处,返回 yield 的数据。如果没有可以用来接收数据的变量,则和 next(generator) 效果一样。生成器没有启动时,第一次使用 send() ,必须先发送一个 send(None) ,因为此时还没有 yield 表达式可以来接收值。

    yield from <generator> 它可以让两个生成器交互。可以从当前生成器,进入到另一个生成器执行,执行完毕后,再回到当前生成器。

    def inner():
        print('enter inner')
        value = yield 2  # 第二次截止到: yield 2 ;  # 第三次从赋值开始: value = send传递过来的值
        print('inner value:',value)
        yield 3  # 第三次完毕
        return 'inner_return'  # 第四次开始
    
    def outer():
        print('outer entered')
        yield 1   # 第一次截至到这里
    
        value = yield from inner()  # 第二次起始:进入另一个生成器
    
        yield 4  # 第四次结束
        print('back to outer')  # 第五次开始
        print('value is :', value)  # 第五次结束,并抛出 StopIteration 异常
    
    o = outer()
    print(next(o))  # 没啥好说的,往下走
    print(next(o))  # 没啥好说的,往下走到 yield 2
    print(next(o))  # 没法发送数据,所以 yield 2 前面的 value 会是 None
    print(next(o))  # 没啥好说的,不停的往下走
    print(next(o))  # 没啥好说的,不停的往下走
    
    # ==================================================
    o = outer()
    print(o.send(None))  # o.send(None) 等同于 next(o),第一次必须发送 None,先走到 yield 代码处
    print(o.send('HH'))  # 尽管发了一个数据:HH,但是第1次 yield 1 前面没有接收这个数据的变量,所以直接走向下一个 yield
    print(o.send('HHH'))  # 上一次 yield 停止的地方:value = yield 2 有个变量可以接收值,所以给 value 赋值,然后走到下一个 yield 处
    print(o.send('HHHH'))
    print(o.send('HHHHH'))
    
    

    for 循环

    for 循环,可以循环迭代器,生成器,可迭代对象。它的原理,就是先执行要循环的对象的__iter__() 方法,获得一个迭代器,然后执行迭代器的 __next__() 方法,并且在循环完毕时,处理一下 StopIteration 异常。虽然我们写函数式的生成器时没有__iter__() 方法,但是它已经内置了这个方法。

    譬如:

    def it():
        yield 1
    
    ge = it()
    print(dir(ge))
    i = ge.__iter__()
    print(dir(i))
    print(next(i))
    
    
    class it(object):
        def __iter__(self):
            return iter([1,2,3])
    
    # ------- for --------
    for i in it():
        print(i)
    
    # ------- 原理 --------
    i = it().__iter__()
    while True:
        try:
            print(next(i))
        except StopIteration:
            break
    
  • 相关阅读:
    重构技巧 引入Null对象
    python yield
    todo
    Python 函数式编程学习
    Python 修饰器
    socket
    Exception、RuntimeException
    设计模式
    线程池
    VMware异常关闭后再次启动提示“以独占方式锁定此配置文件失败”!!!
  • 原文地址:https://www.cnblogs.com/wztshine/p/15405377.html
Copyright © 2011-2022 走看看