20180718 (生成器函数,表达式和列表字典集合推导式)

一.生成器和生成器函数

生成器的实质就是迭代器

在Python中有三种方式来获取生成器:

  1.通过生成器函数           yield 就是生成器函数

  2.通过生成器表达式创建生成器

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

例如:

  def func():

    print("我是周杰伦")

    yield "昆凌"

  ret = func()      =====>这里是通过func()函数来创建一个生成器     ====>如果光执行func()   打印出来的是空   没有东西,因为它本身是个生成器,但没有为它赋予值

  print(ret)          =======>打印出来的结果是生成器的内存地址

例如:       .__next__()   是下一个的意思,向下执行

  def func():

    print("我是周杰伦")

    yield "昆凌"

  g = func()

  print(g.__next__())   ======>打印出来的结果是"我是周杰伦"  "昆凌"

例如:

  def func():

    print("我是周杰伦")

    return "昆凌"

  print(func())               ======>打印出来的结果是"我是周杰伦"   "昆凌"

return 与 yield 的区别

1.return    直接返回结果,结束函数的调用

2.yield      返回结果,可以让函数分段执行

例如:

  def func():

    print("AA")

    yield "aa"

    print("BB")

    yield "bb"

    #print("CC")              =====>如果没有这两行或者是没有最后一行 ,最后一个.__next__()仍会继续执行,但是没有东西,所以就会报错

    #yield "cc"

  g = func()

  print(g.__next__())           ======> "AA" "aa"

  print(g.__next__())           ======>"BB" "bb"

  print(g.__next__())           ======>(如果存在print("CC")和yield "cc"这两行  执行出来CC和cc)

生成器有一个有点就是节省内存

例如:    运用生成器的好处就是可以节省内存,需要一件的时候就拿一件,但是最后的结果还是这100件

  def func():                                 

    i = 1

    while i < 101:

      yield "衣服%s" % i

      i = i + 1

  g = gen()

  print(g.__next__())                  ===>衣服1                  ,__next__() 到哪里,就拿到哪里

  print(g.__next__())                  ===>衣服2

例如: 

  def func():

    lst = []

    for i in range(1,101):

      lst.append("衣服%s" % i)

    return lst                                    =========>这个执行出来的是将全部的衣服放进列表里全部打印出来   这样耗时又费空间内存

  func()

例如:

  def func():

    yield 11

    yield 22

    yield 33

  g = func()                  =====>拿到的是生成器,生成器的本质是迭代器,迭代器可以被迭代,生成器的本身就是迭代器,所以生成器可以直接执行for循环

  for i in g:                                ======>for循环本质是执行的是  .__next__()

    print(i)                    =====>打印出来的结果是11 22 33遍历循环

send 和 .__next__()的区别:

1.send()  和  .__next__()   都可以让生成器向下执行一次

2.send可以给上一个yield传一个值,但是不能给最后一个yield传值,并且在第一次执行生成器的时候不能使用send()

例如: send例子

  def func():

    print("AA")

    a = yield "aa"

    print(a)

    print("BB")

    yield "bb"

    print(a)

    print("CC")

    yield "cc"

  g = func()

  print(g.__next__())             ====>"AA""aa"

  print(g.send(1))                  =====> 1 "BB" "bb"

  print(g.__next__())             =====> "CC" "cc"

二.列表的推导式

语法:[最终结果 for 变量 in 可迭代对象 if 筛选]   

列表推导式比较耗内存,得到一个列表

例如:  (常规写法)

  lst = []

  for i in range(1,15):

    lst.append("python%s" % i)

  print(lst)                  ======>打印出来是["python1","python2","python3"......"python14"]

例如:    列表推导式写法

  lst = ["python%s" % i for i in range(1,15)]

  print(lst)

例如:打印1~100能被3整除的数   放在列表里

  lst = [i for i in range(1,101) if i %3 == 0)]

例如:打印100以内能被3整除的数的平方

  lst = [i**2 for i in range(1,101) if i %3 == 0]

例如:找出名字中带有两个e的人的名字

   names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' ,'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']]

  lst = [ii for i in names for ii in i if ii.count("e") == 2]

三.生成器表达式    

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

语法:(结果 for 变量 in 可迭代对象 if 筛选)   

生成器表达式几乎不占内存,获取的是一个生成器

例如:

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

  print(gen)             =====>打印出来的是生成器    只有内存地址

例如:

  gen = ("麻花藤我第%s次爱你" % i for i in range(10))

  for i in gen:

    print(i)

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

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     g2的数据来源于g1

  print(list(g))          ======>111  [222]                 获取g中的数据,这时func()才会被执行,打印111,获取到222  g执行完毕

  print(list(g1))        ======>  []        #获取g1的数据  g1的数据来源是g  但是g已经取完了   g1也就没有了数据

  print(list(g2))        ======>  []        #同样g2也没有数据

五.字典推导式

语法:{结果 for 变量 in 可迭代对象 if 筛选}    ====>结果是k:v

例如:

  dic = {"a":1,"b":2}

  new_dic = {dic[key]:key for key in dic}

  print(new_dic)

例如:

  lst1 = ["AA","BB","CC"]

  lst2 = ["aa","bb","cc"]

  dic = {lst1[i] : lst2[i] for i in range(len(lst1))}

      =======>{"AA":"aa","BB":"bb","CC":"cc"}

六.集合推导式   (自动去重)

集合推导式可以帮我们直接生成一个集合,集合的特点是无序,不重复,所以集合推导式自带去重功能

语法:{结果 for 变量 in 可迭代对象 if 筛选}    ====>结果是k

例如:

  lst = ["AA","BB","CC","DD","AA","BB"]

  s = {i for i in lst}

  print(s)    ======>{"AA","BB","CC","DD"}

变态面试题

  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]

  for n in [2,10]:                #n的值为2   10

    g = (add(n,i) for i in g)

当程序循环第一次的时候   n = 2   但是循环没有结束,不执行

  g = (add(n,i) for i in test())

当程序循环第二次的时候  n = 10   到print()的时候才执行

  g = (add(n,i) for i in (add(n,i) for i in test()))

当时这个时候不执行,只有当程序执行到print的时候,才会将n的值带入 此时n = 10

 

原文地址:https://www.cnblogs.com/lhy979/p/9330026.html