主要内容:
1. 生成器:生成器的实质就是迭代器,在python中有三种方式可以获取生成器:
通过生成器函数
通过各种推导式来实现生成器
通过数据的转换也可以实现生成器
2. 生成器函数
a: 函数中包含了yield的就是生成器函数.
注意:生成器函数被执行,获取的是生成器,而不是函数的执行
def fn():
print("张杰")
yield "谢娜" #函数中包含yeild说明该函数不是一个普通的函数,而是生成器函数
print("你好啊")
yield "hi"
print("明日之子")
yield 'pick田四火'
s = fn() #创建一个生成器
print(s.__next__())
print(s.__next__())
print(s.__next__()) #最后一个yield执行完毕,在执行yield会报错.
#return 直接返回函数结果,结束调用
#yeild 返回结果,可以让函数分段进行
b: 注意
def func(): print("张杰") yield "谢娜" #函数中包含yeild说明该函数不是一个普通的函数,而是生成器函数 print("明日之子") yield 'pick田四火' g1 = func() #表示两个相同的生成器,第一个从头开始指向下一个元素,第二个也是从头开始指向元素. g2 = func() print(g1.__next__()) #张杰谢娜 print(g1.__next__()) #明日之子,田四火 print("==============") print(g2.__next__()) #张杰谢娜
c: 生成器的优点,可以节约内存,
例题:例如老男孩教育要给每个培训的学员定制一套衣服,共10000套.
def fn(): lst = [] for i in range(1,10001): lst.append('衣服%s' % i) return lst s = fn() print(s)
缺点:一次性全部拿出来,会很占用内存.
def fn(): lst = [] i = 1 while i < 100001: yield '衣服%s' % i i = i + 1 g = fn() print(g.__next__()) print(g.__next__()) print(g.__next__())
使用生成器.一次就一个,用多少生成多少,生成器是一个一个的指向下一个,不会回去,__next__()到哪,指针就指到哪.下一次继续或许指针指向的值
d: 拿到的是生成器. 生成器的本质是迭代器. 迭代器可以被迭代 生成器可以直接for循环
def func(): yield 11 yield 22 yield 33 g = func() #拿到的是生成器,生成器的本质是迭代器,迭代器可以被迭代,生成器可以直接for循环 for i in g: print(i)
e: list[g]
def func(): yield 11 yield 12 yield 13 yield 14 g = func() #获取生成器 lst = list(g) #括号里必须为可迭代对象 print(lst)
3. send: send和__next__一样,都可以让生成器执行到下一个yield.
send和__next__的区别:
send():也可以让生成器向下执行一次,给上一个yield传一个值,第一个不能用send,最后一个也不要传值.
__next__:可以使生成器向下执行一次.
def eat(): print("我吃什么啊") a = yield "馒头" print("a=",a) b = yield "大饼" print("b=",b) c = yield "韭菜盒子" print("c=",c) yield "GAME OVER" gen = eat() # 获取⽣成器 print(gen. __next__ ()) #到yield结束,返回馒头 print(gen.send("胡辣汤")) #可以给上一个yield传值,a = 胡辣汤 print(gen.send("狗粮")) #可以给上一个yield传值,b = 狗粮 print(gen.send("猫粮")) #可以给上一个yield传值,c = 猫粮
4. 列表推导式
语法:[最终结果 for 变量 in 可迭代对象 ]
语法:[最终结果 for 变量 in 可迭代对象 if 条件]
生成列表,里面装1-14数据
普通模式
li = [] for i in range(1,15): li.append('python%s期' % i) print(li)
采用推导式
li = ['python%s期' % i for i in range(1,15)] print(li) # ['python1期', 'python2期', 'python3期', 'python4期', 'python5期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期', 'python11期', 'python12期', 'python13期', 'python14期']
获取100以内能被3整除的数的平方
li = [i*i for i in range(101) if i % 3 == 0 ] print(li)
寻找名字中带有两个e的人的名字
names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' , 'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']] lst = [name for first in names for name in first if name.count("e") == 2] print(lst)
5. 字典推导式
dic = {"a":"b", "c":"d"},把字典中的key和value互换:
dic = {'a':'b','c':'d'} new_dic = { dic[key]:key for key in dic} print(new_dic)
lst1作为key,lst2作为value
lst1 = ["alex", "wusir", "taibai", "ritian"] lst2 = ['sb', "很色", "很白", "很牛"] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} #取他们的索引 print(dic)
6. 集合推导式
lst = ['马化腾','马化腾','王建中','张建忠','张雪峰','张雪峰'] s = {i for i in lst} print(s)
7. 生成器表达式
把列表推导式[]变成(),就成为生成器表达式
格式(最终结果 for 变量 in 可迭代对象)
gen = ("麻花藤我第%s次爱你" % i for i in range(10)) print(gen) #<generator object <genexpr> at 0x0000021314580F68>
打印的结果是一个生成器,我们可以用for循环来循环这个生成器.
gen = ("麻花藤我第%s次爱你" % i for i in range(10)) for i in gen: print(i)
生成器表达式也可以进行筛选:
gen = (i for i in range(100) if i % 3 == 0) for e in gen: print(e)
生成器表达式和列表推导式的区别:
a: 列表推导式比较耗内存,一次性加载,生成器表达式几乎不占用内存,使用的时候才分配和使用内存.
b: 得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是一个生成器.
形象的说明:列表推导式:直接拿到一筐子鸡蛋,生成器表达式:拿到一个老母鸡,需要的时候母鸡就给你下鸡蛋.
生成器的惰性机制:
生成器只有在访问的时候才取值,说白了,你找他要,他才给你,不找他要,他不会执行.
# 生成器的惰性机制: def func(): print(111) yield 222 g = func() #通过生成器函数获得的生成器 g1 = (i for i in g) #通过生成器表达式获得的生成器g1 g2 = (i for i in g1) #生成器g2 print(list(g)) #获取g中的数据,这是func()才会执行,打印111,获取到222,g完毕. print(list(g1)) #获取g1中的数据,g1 的数据来源g,但是g已经取完了,g1也就没有数据了. print(list(g2))
有关生成器表达式的惰性机制的一道面试题
def add(a, b): return a + b def gen(): for r_i in range(4): yield r_i g = gen() for n in [2, 10]: g = (add(n, i) for i in g) #生成器的惰性机制,生成器只有在访问的时候才取值,说白了,你找他要,他才给你值.不找他要不会给你的 print(list(g)) #不到最后不会拿值:惰性机制.
def add(a, b): return a + b def test(): for r_i in range(4): yield r_i # g = test() # g = (add(n, i) for i in g) #生成器的惰性机制,生成器只有在访问的时候才取值,说白了,你找他要,他才给你值.不找他要不会给你的 g = (add(10, i) for i in (add(10, i) for i in 0,1,2,3) #第二次执行的时候替换后面的g g = (add(10, i) for i in 10,11,12,13 print(list(g)) # lst(g) = [20,21,22,23]