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异常'))

 

posted @ 2021-02-12 14:53  junffzhou  阅读(374)  评论(0编辑  收藏  举报