迭代器
可迭代
可迭代协议:含有__iter__方法
可迭代的,一定可以被for循环
可被for循环(可迭代的)
- 1, list
- 2, dic
- 3, str
- 4, set
- 5, tuple
- 6, f = open()
- 7, range()
- 8, enumerate (枚举)
- 迭代器
- 生成器
# list l = [1, 2, 3, 4] for i in l: print('i', i) # dic d = {'id': 1, 'name': 'sun', 'age': 19} for key, value in d.items(): print(key, value) # str s = 'hello world' for i in s: print(i) # set se = {1, 2, 4, 6, 6} for i in se: print(i) # tuple t = (1, 2, 3, 4) for i in t: print('t', i) # f = open() f = open('content.txt', 'r') for i in f: print('f', i) # range() for i in range(1, 10): print('range', i) # enumerate() 每当你需要向上计数时,每次一个数字,同时循环遍历一个迭代器, enumerate函数就会派上用场。 bank_names = [ "工商银行", "农业银行", "中国银行", "建设银行", "招商银行", "浦发银行", "广发银行", "广州银行", "邮储银行", "平安银行", "农商银行", "兴业银行", "华夏银行", "交通银行", "光大银行", "中信银行", ] banks = [{"id": i, "name": v} for i, v in enumerate(bank_names, 1)] print(banks) # 迭代器 # 生成器
迭代器
迭代器协议, 含有__iter__和__next__方法
迭代器一定可迭代, 可迭代的通过调用__iter__方法就能得到一个迭代器
""" 迭代器协议, 含有__iter__和__next__方法 """ # 把列表变成一个迭代器 """ 构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。 比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。 因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的next方法) """ L = [i for i in range(10)] iterator = iter(L) print(iterator) for i in iterator: print('iterator', i) for i in iterator: print('iterator xx', i) # 没有了 # 以斐波那契数列为例实现一个迭代器 class Fib(object): def __init__(self, n): self.previous = 0 self.current = 1 self.n = n def __iter__(self): return self def __next__(self): if self.n > 0: value = self.current self.current = self.current + self.previous self.previous = value self.n -= 1 # this is a flag return value else: raise StopIteration() f1 = Fib(10) print([i for i in f1])
生成器
本质上就是迭代器,不过更简洁
""" 知道迭代器之后,就可以正式进入生成器的话题了。 普通函数用 return 返回一个值,和 Java 等其他语言是一样的,然而在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象, 生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁 """ # 最简单的生成器函数 def generator(n): yield n * 2 # 1 g = generator(2) print(g) print(next(g)) # 2 g = generator(5) for i in g: print(i) # 用生成器实现斐波那契数列 def fib(n): previous, current = 0, 1 while n > 0: n -= 1 yield current previous, current = current, previous + current f = fib(10) print([i for i in f]) # 生成器表达式 g = (x * 2 for x in range(10)) print([i for i in g]) # print(next(g)) # 取完值再取会报错
表现形式
生成器函数
1,只有含有yield关键字的函数就是生成器函数
,2,特点
- 1, 调用函数之后不执行, 返回一个生成器
- 2, 每次调用next取得一个值
- 3, 取完最后一个, 再执行next会报错
生成器表达式
主要特征:()
g = (i for i in range(1,11)) # 生成一个生成器 for i in g: # 通过for循环取值 print(i)
特点
1,调用函数之后不执行,返回一个生成器
2,每次调用next取得一个值
3,取完最后一个值,再调next会报错
4,数据只能取一次,取完就没了
5,惰性运算
取值
1,for循环
g = (i for i in range(1,11)) # g是一个生成器 for i in g: # 通过for循环取值 print(i)
2,__next__
g = (i for i in range(1,11)) # g是一个生成器 print(g.__next__()) # 1 print(g.__next__()) # 2 print(g.__next__()) # 3
3, send
1,send获取下一个值的效果和next效果一致
2,只是在获取下一个值的时候, 给上一个值的位置传递一个新的值
3,注意
- 第一次使用的时候, 用next获取下一个值
- 最后一个yield不能接收外部的值
简单例子
def generator(): print('begin') ret = yield 'this is beginning' print('receive content', ret) print('end') yield 'b' g = generator() print(next(g)) b = g.send("hi, I'm sending") print('this is should b :', b)
求移动平均值且预激活装饰器
def init_generator(func): """ # 有预激活生成器作用的装饰器 :param func: :return: """ def inner(*args, **kwargs): g = func(*args, **kwargs) g.__next__() return g return inner @init_generator def generator(): total = 0 # =0用来做初始化的 count = 0 # =0用来做初始化的 __avg = 0 # =0用来做初始化的 while True: num = yield __avg # num 是通过send传过来的 total += num count += 1 __avg = total / count _avg = generator() print(_avg.send(10)) # 10 / 1 print(_avg.send(20)) # (10 + 20) / 2 print(_avg.send(30)) # (10 + 20 + 30) / 3
4,数据类型的强转
g = (i for i in range(100)) print(g) print(list(g))