生成器和生成器表达式

一 . 生成器

  生成器就是迭代器

  生成器的特点和迭代器一样.

    1.省内存

    2.惰性机制

    3.只能向前

  在python中有三种方式获取生成器

    1.通过生成器函数

    2.通过各种推导式来实现生成器

    3.通过数据的转换也可以获取生成器

  简单的生成器函数

def func():    
    print("111")    
    yield 222 

ret = func() 
print(ret) 

结果: 
<generator object func at 0x10567ff68>

   yield和return的效果是一样的.  有什么区别呢?  yield是分段来执行一个 函数. return呢? 直接停止执行函数. 

def func():    
    print("111")    
    yield 222    
    print("333")    
    yield 444 

gener = func() 
ret = gener.__next__() 
print(ret) 
ret2 = gener.__next__() 
print(ret2) 
ret3 = gener.__next__()  # 最后⼀一个yield执行完毕. 再次__next__()程序报错, 也就是 说. 和return无关了了. 
print(ret3) 

结果: 111 
Traceback (most recent call last): 
222 
333  
File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in <module> 
444    
    ret3 = gener.__next__()  # 最后⼀一个yield执行完毕. 再次__next__()程序报错, 也 就是说. 和return无关了了. StopIteration

  send和__next__()区别:

    1. send和next()都是让⽣生成器向下走一次

    2. send可以给上一个yield的位置传递值, 不能给后一个yield发送值. 在第一次执行生
  成器代码的时候不能使用send()

生成器可以使用for循环来循环获取内部的元素

def func():    
    print(111)    
    yield 222    
    print(333)    
    yield 444    
    print(555)    
    yield 666 

gen = func() 
for i in gen:    
    print(i) 

结果: 
111 
222 
333 
444 
555 
666

二 . 推导式

  列表推导式:

lst = [i for i in range(1, 15)] 
print(lst)
 

列表推导式的常用写法:     

  [ 结果 for 变量 in 可迭代对象]

 生成器表达式和列表推导式的语法基本上是一样的. 只是把[]替换成() 

gen = (i for i in range(10)) 
print(gen) 

结果: 
<generator object <genexpr> at 0x106768f10> 

生成器表达式也可以进行筛选: 

# 获取1-100内能被3整除的数 
gen = (i for i in range(1,100) if i % 3 == 0) 
for num in gen:    
    print(num) 

# 100以内能被3整除的数的平方 
gen = (i * i for i in range(100) if i % 3 == 0) 
for num in gen:    
    print(num) 

# 寻找名字中带有两个e的人的名字 
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],          ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']] 

# 不用推导式和表达式 
result = [] 
for first in names:    
    for name in first:        
        if name.count("e") >= 2:            
            result.append(name) 

print(result) 

# 推导式 
gen = (name for first in names for name in first if name.count("e") >= 2) 
for name in gen:    
    print(name)    

生成器表达式和列表推导式的区别: 

  1. 列表推导式比较耗内存. 一次性加载. 生成器表达式几乎不占用内存. 使用的时候才分配和使用内存

  2. 得到的值不一样. 列表推导式得到的是一个列表. 生成器表达式获取的是一个生成器.

 生成器的惰性机制: 生成器只有在访问的时候才取值. 说白了. 你找他要他才给你值. 不找他要. 他是不会执行的. 

def func():    
    print(111)    
    yield 222 

g = func()  # 生成器g 
g1 = (i for i in g) # 生成器g1. 但是g1的数据来源于g 
g2 = (i for i in g1)    # 生成器g2. 来源g1 

print(list(g))  # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕. 
print(list(g1))  # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1也就没有数据了 
print(list(g2))  # 和g1同理

  深坑==> 生成器. 要值得时候才拿值. 

字典推导式: 

# 把字典中的key和value互换 
dic = {'a': 1, 'b': '2'} 
new_dic = {dic[key]: key for key in dic} 
print(new_dic) 

# 在以下list中. 从lst1中获取的数据和lst2中相对应的位置的数据组成一个新字典 
lst1 = ['jay', 'jj', 'sylar'] 
lst2 = ['周杰伦', '林俊杰', '邱彦涛'] 
dic = {lst1[i]: lst2[i] for i in range(len(lst1))} 
print(dic)

集合推导式:

lst = [1, -1, 8, -8, 12] 
# 绝对值去重 

s = {abs(i) for i in lst} 
print(s)

  总结: 推导式有, 列表推导式, 字典推导式, 集合推导式, 没有元组推导式    

      生成器表达式: (结果 for 变量 in 可迭代对象 if 条件筛选)     

   生成器表达式可以直接获取到生成器对象. 生成器对象可以直接进行for循环. 生成器具有惰性机制

def add(a, b):    
    return a + b

def test():    
    for r_i in range(4):        
        yield r_i

g = test()  

for n in [2, 10]:    
    g = (add(n, i) for i in g)

print(list(g))

结果:
[20,21,22,23]

   友情提示: 惰性机制, 不到后不会拿值

  这个题要先读一下. 然后自己分析出结果. 后用机器跑一下. 

原文地址:https://www.cnblogs.com/xiangweilai/p/9468386.html