zoukankan      html  css  js  c++  java
  • python3之迭代器和生成器

    一、迭代器

    一) 迭代

    重复多次,可以用 for-in 循环
    字符串,元组,列表,字典,range都是可迭代的,但不是迭代器,可用来创建迭代器

    二) 迭代器

    包含 __iter__() 方法和 __next__() 方法
    可以通过 next() 内置函数调用 __next__() 方法

    __iter__() 方法返回一个定义了 __next__() 方法的可迭代的对象本身
    __next__() 方法迭代出对象的元素

    迭代原理

    从迭代器对象的第一个元素开始访问,直到所有元素被访问完结束
    当元素用尽时, 再次调用 next() 函数会引发 StopIteration 异常,告知 for循环终止
    迭代器只能往前不能后退,可以记住遍历的位置

    示例

    tulp = ('asd', 123, 'qwe', 4567, 6, 'a')
    dic = dict(key1=1, key2='asd', key3=234, key4='q', key5='qwerty')
    
    tulp_iter = iter(tulp)
    #调用next()内置函数迭代访问迭代器元素
    print(next(tulp_iter))
    print(next(tulp_iter))
    print(next(tulp_iter))
    print(next(tulp_iter))
    print(next(tulp_iter))
    print(next(tulp_iter))
    #引发 StopIteration 异常
    print(next(tulp_iter))
    
    dic_iter = iter(dic)
    #调用next()内置函数访问迭代器元素,返回字典key
    print(next(dic_iter))
    print(next(dic_iter))
    print(next(dic_iter))
    print(next(dic_iter))
    print(next(dic_iter))
    #引发 StopIteration 异常
    print(next(dic_iter))

    三) 自定义迭代器

     类中需要实现 __iter__() 和 __next__() 两个方法

    示例

    正向迭代

    class Item:
        def __init__(self, data):
            self.data = data
            self.index = 0
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if (self.index < len(self.data)):
                self.index += 1
                return self.data[self.index - 1]
            else:
                raise StopIteration('迭代完了哦')
    
    Ite = Item('qazwsx')
    print(next(Ite))
    print(next(Ite))
    print(next(Ite))
    print(next(Ite))
    print(next(Ite))
    print(next(Ite))
    #注释该行代码,否则引发 raise 异常
    #print(next(Ite))
    [ print(elem) for elem in Item('QAZ123WSX')]

    反向迭代

    class Reverse:
        def __init__(self, data):
            self.data = data
            self.index = len(data)
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.index == 0:
                raise StopIteration
            self.index = self.index - 1
            return self.data[self.index]
    
    [ print(elem) for elem in Reverse('hello world!') ]

    二、生成器

    含有 yield 关键字的函数被称为生成器(generator)
    生成器和迭代器相似,同样可以使用 for-in 遍历和 next() 内置函数

    一) 生成器创建

    两种方法创建生成器

    for循环的生成器表达式
    
    含有yield关键字的函数

    1 生成器表达式

    格式

    (表达式 for 循环计数器 in iterable)

    示例

    sum(i*i for i in range(10))
    
    data = 'Python generator'
    list(data[elem] for elem in range(0, len(data)))
    list(data[elem] for elem in range(len(data)-1, -1, -1))

    2 含有yield关键字的函数

    示例

    def gener(start, end):
        sum = 0
        for i in range(start, end+1):
            sum += i
            yield sum
    
    Sum = gener(1,10)
    print(next(Sum))
    print(next(Sum))
    print(next(Sum))
    print(next(Sum))
    print('interrupt')
    print(next(Sum))
    print(next(Sum))
    print(next(Sum))
    print(next(Sum))
    print(next(Sum))
    
    [ print(elem) for elem in gener(20,30) ]
    
    print(list(gener(30,40)))
    print(tuple(gener(30,40)))

    二) 生成器的方法

    1 send() 方法

    类似于 next() 方法,但是 next() 方法 不能从外部接收参数, send() 方法可以从外部为 yield 语句的表达式传入一个值
    第一次启动生成器可以使用 next() 或者 send(None)

    示例

    def square_gen():
        i = 0
        out_val = 0
        while True:
            #使用out_val 接收send() 方法传入的值
            out_val = (yield out_val+2) if out_val is not None else (yield i**2)
            if out_val is not None:
                print('---%d---'% (out_val))
            i += 1
    
    sq = square_gen()
    print(next(sq))
    print(next(sq))
    print(sq.send(8))
    print(next(sq))
    print(next(sq))
    
    其中:
    第一次调用next() 方法,表示启动生成器,等效于调用 send(None) 方法,out_val使用默认值0,此时i=0,返回 out_val+2 的值
    第二次调用next() 方法,没有传入out_val值, out_val=None ,此时i=1,返回 i**2 的值
    第一次调用send() 方法,out_val=8,此时i=2,返回 out_val+2 的值
    第三次调用next() 方法,没有传入out_val值, out_val=None ,此时i=3,返回 i**2 的值
    第四次调用next() 方法,没有传入out_val值, out_val=None ,此时i=4,返回 i**2 的值

    2 close() 方法

    关闭生成器,再次使用生成器会引发StopIteration异常

    示例

    def square_gen():
        i = 0
        out_val = 0
        while True:
            #使用out_val 接收send() 方法传入的值
            out_val = (yield out_val+2) if out_val is not None else (yield i**2)
            if out_val is not None:
                print('---%d---'% (out_val))
            i += 1
    
    sq = square_gen()
    print(sq.send(None))
    print(next(sq))
    print(sq.send(8))
    #关闭生成器
    sq.close()
    #再次使用生成器会引发StopIteration异常
    print(next(sq))

    3 throw() 方法

    在生成器内部(yield 语句)引发一个异常

    示例

    def square_gen():
        i = 0
        out_val = 0
        while True:
            #使用out_val 接收send() 方法传入的值
            out_val = (yield out_val+2) if out_val is not None else (yield i**2)
            if out_val is not None:
                print('---%d---'% (out_val))
            i += 1
    
    sq = square_gen()
    print(sq.send(None))
    print(next(sq))
    print(sq.send(8))
    #在生成器内部即语句out_val=(yield out_val+2) if out_val is not None else (yield i**2)处引发一个ValueError异常
    sq.throw(ValueError('手动引发的ValueError异常'))
  • 相关阅读:
    从运维域看 Serverless 真的就是万能银弹吗?
    C#技术漫谈之垃圾回收机制(GC)(转)
    题解 hdu4624 Endless Spin
    JS递归删除所有子元素【原】
    Asp.Net 生成验证图片
    mouseover显示层mouseout隐藏层,并且在鼠标放上层时显示层【原】
    C# yield关键字的使用
    MS SQL SERVER中的临时表
    猫 老鼠 人的编程题
    面试题:接口和抽象类的区别 【转】
  • 原文地址:https://www.cnblogs.com/gudanaimei/p/13463761.html
Copyright © 2011-2022 走看看