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