python 学习篇12 -生成器和各种推导式

时间:2018-12-11
本文章向大家介绍python 学习篇12 -生成器和各种推导式,主要包括python 学习篇12 -生成器和各种推导式相关应用实例、知识点总结和注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一、生成器
 
        1、生成器的本质就是迭代器,一个一个的创建对象
        2、创建生成器的方式
            1、生成器函数
            2、通过生成器表达式来获取生成器
            3、通过数据的转化也可以获取生成器
二、生成器函数
        生成器函数中包含yield,返回数据和return差不多
不同点:
        return 会立即结束这个函数的执行
        yield可以分段的执行一个函数
 
  
def func():
    print('今天天气如何?')
    yield '晴天'
    print('明天天气如何?')
    yield '阴天'
    print('后天天气怎么样')
    yield '谁知道呢'

ret = func() # 执行函数,此时没有运行函数,此时拿到的是一个生成器
print('返回值是:',ret) # 返回值是: <generator object func at 0x000001AA87C45BA0>

print(ret.__next__()) # 第一次执行__next__的时候,函数才开始执行
print(ret.__next__()) # 执行下一个yield
print(ret.__next__()) # StopInteration
生成器函数能向下执行到两个条件:
 
 1、 __next__(),执行到下一个yield
 2、send(),执行到下一个yield,给上一个yield位置传值
  
  所有的生成器都是迭代器都可以使用for循环
  都可以shiyonglist()函数来获取到生成器内的所有元素
例子
第一种
# 买100件衣服
def buy():
    st = []
    for i in range(1,101):
        lst.append("衣服%s"% i)
    return lst

lst = buy()
print(lst)

第二种 用生成器
def buy():
    for i in range(101):
    yield "衣服%s"%i

gen = buy() #生成器或者迭代器的好处:节省内存
print(gen.__next__()) # 需要一件拿一件
print(gen.__next__())
print(gen.__next__())


for yifu in gen: # 迭代器.__next__()
    print(yifu)

lst = list(gen) # 内部使用的是for 循环 ->__next__()
print(lst)

send()  执行到下一个yield,给上一个yield位置传值

def func():
  print('你喜欢什么水果')
  a = yield "芒果"
  print("a", a)
  b = yield "苹果"
  print("b", b)
  c = yield "柚子"
  print("c",c)

gen = func()

print(gen.__next__())
print(gen.__next__())
print(gen.__next__())

# 你喜欢什么水果
# 芒果
# a None
# 苹果
# b None
# 柚子
结论:执行函数时,a,b,c 都返回None

gen = func()

print(gen.__next__()) # 第一个位置用send没有任何意义
print(gen.send("篮球")) # 给上一个yield位置传值
print(gen.send("足球"))

# 你喜欢什么水果
# 芒果
# a 篮球
# 苹果
# b 足球
# 柚子
 生成器中记录的是代码而不是函数的运作
def func():
    print('哈哈')
    yield ''大风
 
gen = func() #  创建生成器,此时运行会把生成器函数中的代码记录在内存
 
     当执行到__next__(),运行此空间中的代码,运行到yield结束
 
   优点:节省内存,生成器本身就是代码,几乎不占内存
    特点:惰性机制,只能向前,不能反复
 
三、各种推导式
 
    1、列表推导式  [结果 for循环 if判断]
# 生成列表.类表中装的数据是 1-100之间所有的偶数的平方
lst =[i ** 2 for i in range(1,101) if i %2 == 0]
print(lst)
# # 寻找名字中带有两个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)

2、字典推导式{结果(k,v)for 循环 if判断} 

# 把字典的key和value互换, 生成新字典
dic = {"主食": "炒面", "副食": "小拌菜", "":"疙瘩汤"}
dic1 = {v:k for k,v in dic.items() }
print(dic1)
3、集合推导式 {结果(k) for 循环 if 判断}
 
      没有元组推导式
 
四、生成器表达式
 
    (结果  for 循环  if)
g = (i for i in range(10)) # 生成器表达式
print(g) # <generator object <genexpr> at 0x000001F7769F5938>

yield from  # 可以把一个可迭代对象分别进行yield返回 

def func():
  lst = ["水果%s"% i for i in range(10)]
  yield from lst

gen = func()

ret = gen.__next__()
print(ret)
ret = gen.__next__()
print(ret)

# 水果0
# 水果1

添加 写代码的注意事项 

def func(name,info):
'''
    函数功能
    :param name: 参数name
    :param info: 参数 info
    :return: 返回什么内容
    :creator:创建者
    :author :作者
    :date:时间
'''

a = func
print("***")
print("***")
print("***")
print("***")
...


a('','') # 中间的代码内容过长,查找a的名字
print(a.__name__) # 看到函数的真实的名字(相对)
print(a.__doc__) # 函数的功能
面试相关的有坑的题
 
深坑,需要值的时候才去拿值
def func():
    print(111)
    yield 222

g = func() # 创建生成器
g1 = (i for i in g) # 生成器表达式,生成器g1,g1的数据来源于g
g2 = (i for i in g1) # 生成器表达式 生成器g2,g2的数据来源于g1

print(list(g)) # 获取g中的数据,这时func()才会被执行,打印111,获取222,g完毕
print(list(g1)) # 获取g1的数据,g1的数据来源时g,但是g已经被取完了,所有g1没有数据
print(list(g2)) # 与g1同理
# 如下代码打印的结果分别是什么
def extendList(val,list=[]): # 多次调用使用同一个列表
    print(id(list))
    list.append(val) # 把元素添加到列表,然后返回列表
    return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList("a")

print("list1 = %s"%list1)
print("list2 = %s"%list2)
print("list3 = %s"%list3)


# list1 = [10, 'a']
# list2 = [123]
# list3 = [10, 'a']