1. 生成器

什么是⽣成器?⽣成器实质就是迭代器。
在python中有三种⽅式来获取⽣成器:
1. 通过⽣成器函数
2. 通过各种推导式来实现⽣成器
3. 通过数据的转换也可以获取⽣成器
⾸先,我们先看⼀个很简单的函数:
def func():
  print("")
  return 222
ret = func()
print(ret)

结果:
111
222
将函数中的return换成yield就是⽣成器
def func():
  print("")
  yield 222
ret = func()
print(ret)

结果:
<generator object func at 0x10567ff68>
运⾏的结果和上⾯不⼀样,为什么呢?由于函数中存在了yield,那么这个函数就是⼀个⽣成器
函数。这个时候,我们再执⾏这个函数的时候,就不再是函数的执⾏了,⽽是获取这个⽣成器。
如何使⽤呢? 想想迭代器,⽣成器的本质是迭代器,所以,我们可以直接执⾏__next__()来执⾏以下⽣成器。
def func():
  print("")
  yield 222
gener = func() # 这个时候函数不会执⾏. ⽽是获取到⽣成器
ret = gener.__next__() # 这个时候函数才会执⾏. yield的作⽤和return⼀样. 也是返回数据
print(ret)

结果:
111
222
那么我们可以看到,yield和return的效果是⼀样的,有什么区别呢? yield是分段来执⾏⼀个
函数,return呢? 直接停⽌执⾏函数。
def func():
  print("")
  yield 222
  print("")
  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
当程序运⾏完最后⼀个yield,那么后⾯继续进⾏__next__()程序会报错。好了⽣成器说完了,⽣成器有什么作⽤呢? 我们来看这样⼀个需求,老男孩向JACK JONES订
购10000套学⽣服,JACK JONES就比较实在,直接造出来10000套衣服。
def cloth():
  lst = []
  for i in range(0, 10000):
    lst.append("⾐服"+str(i))
  return lst
cl = cloth()
但是呢,问题来了。老男孩现在没有这么多学⽣啊,⼀次性给我这么多,我往哪⾥放啊. 很尴尬啊,最好的效果是什么样呢? 我要1套,你给我1套,⼀共10000套,是不是最完美的。
 
def cloth():
  for i in range(0, 10000):
    yield "⾐服"+str(i)
cl = cloth()
print(cl.__next__())
print(cl.__next__())
print(cl.__next__())
print(cl.__next__())
区别: 第⼀种是直接⼀次性全部拿出来,会很占⽤内存,第⼆种使⽤⽣成器,⼀次就⼀个. ⽤多少⽣成多少。⽣成器是⼀个⼀个的指向下⼀个,不会回去,__next__()到哪,指针就指到哪⼉,下⼀次继续获取指针指向的值。
接下来我们来看send⽅法,send和__next__()⼀样都可以让⽣成器执⾏到下⼀个yield。
def eat():
  print("我吃什么啊")
  a = yield "馒头"
  print("a=",a)
  b = yield "⼤饼"
  print("b=",b)
  c = yield "⾲菜盒⼦"
  print("c=",c)
  yield "GAME OVER"

gen = eat() # 获取⽣成器
ret1 = gen.__next__()
print(ret1)
ret2 = gen.send("胡辣汤")
print(ret2)
ret3 = gen.send("狗粮")
print(ret3)
ret4 = gen.send("猫粮")
print(ret4)
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

2. 列表推导式, ⽣成器表达式以及其他推导式

⾸先我们先看⼀下这样的代码,给出⼀个列表,通过循环,向列表中添加1-14 :
lst = []
for i in range(1, 15):
  lst.append(i)
print(lst)
替换成列表推导式:
lst = [i for i in range(1, 15)]
print(lst)
列表推导式是通过⼀⾏来构建你要的列表,列表推导式看起来代码简单,但是出现错误之后很难排查。
列表推导式的常⽤写法:
[ 结果 for 变量 in 可迭代对象]
例,从python1期到python14期写入列表lst:
lst = ['python%s' % i for i in range(1,15)]
print(lst)
我们还可以对列表中的数据进⾏筛选
筛选模式:
[ 结果 for 变量 in 可迭代对象 if 条件 ]
# 获取1-100内所有的偶数
lst = [i for i in range(1, 100) if i % 2 == 0]
print(lst)
⽣成器表达式和列表推导式的语法基本上是⼀样的,只是把[]替换成()
gen = (i for i in range(10))
print(gen)

结果:
<generator object <genexpr> at 0x106768f10>
打印的结果就是⼀个⽣成器,我们可以使⽤for循环来循环这个⽣成器:
gen = ("麻花藤我第%s次爱你" % i for i in range(10))
for i in gen:
  print(i)
⽣成器表达式也可以进⾏筛选:# 获取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': ''}
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循环,⽣成器具有
惰性机制。

python基础(14):生成器、列表推导式的更多相关文章

  1. python基础-三元表达式/列表推导式/生成器表达式

    1.三元表达式:如果成立返回if前的内容,如果不成立返回else的内容 name=input('姓名>>: ') res='SB' if name == 'alex' else 'NB' ...

  2. Python基础8:列表推导式(list)字典推导式(dict) 集合推导式(set)

    推导式分为列表推导式(list),字典推导式(dict),集合推导式(set)三种 1.列表推导式也叫列表解析式.功能:是提供一种方便的列表创建方法,所以,列表解析式返回的是一个列表格式:用中括号括起 ...

  3. 『Python基础-12』各种推导式(列表推导式、字典推导式、集合推导式)

    # 『Python基础-12』各种推导式(列表推导式.字典推导式.集合推导式) 推导式comprehensions(又称解析式),是Python的一种独有特性.推导式是可以从一个数据序列构建另一个新的 ...

  4. python 三元表达式、列表推导式、生成器表达式、递归、匿名函数、内置函数

    http://www.cnblogs.com/linhaifeng/articles/7580830.html 三元表达式.列表推导式.生成器表达式.递归.匿名函数.内置函数

  5. python 三元表达式、列表推导式、生成器表达式

    一 三元表达式.列表推导式.生成器表达式 一 三元表达式 name=input('姓名>>: ') res='mm' if name == 'hahah' else 'NB' print( ...

  6. Python三元表达式、列表推导式、生成器表达式

    1. 三元表达式 name=input('姓名>>: ') res='SB' if name == 'aaaa' else 'NB' print(res) 2. 列表推导式 #1.示例 e ...

  7. python note 12 生成器、推导式

    1.生成器函数 # 函数中如果有yield 这个函数就是生成器函数. 生成器函数() 获取的是生成器. 这个时候不执行函数# yield: 相当于return 可以返回数据. 但是yield不会彻底中 ...

  8. python基础学习1-列表推导式和字典推导式

    #!/usr/bin/env python # -*- coding:utf-8 -*- #列表推导式 取得100内可以被2整除且不能被3整除的数字 a=[i for i in range(100) ...

  9. python高级编程之列表推导式

    1. 一个简单的例子 在Python中,如果我们想修改列表中所有元素的值,可以使用 for 循环语句来实现. 例如,将一个列表中的每个元素都替换为它的平方: >>> L = [1, ...

随机推荐

  1. Linux CentOS上安装 MySQL 8.0.16

    前言: 因为我需要在我新安装的Linux CentOS系统服务器中安装和配置MySQL服务器,然而对于我们这种Linux使用小白而言在Linux系统中下载,解压,配置MySQL等一系列的操作还是有些耗 ...

  2. ZooKeeper(六):watch机制的原理与实现

    因为ZK有watch机制,可以随时发现一些数据的变化,从而达到数据的及时性. ZK的所有读操作都可以设置watch监视点: getData, getChildren, exists. 写操作则是不能设 ...

  3. .NET Core 数据结构与算法 1-1

    .NET Core 数据结构与算法 1-1 本节内容为顺序表 简介 线性表是简单.基本.常用的数据结构.线性表是线性结构的抽象 (Abstract),线性结构的特点是结构中的数据元素之间存在一对一的线 ...

  4. 转换流读写操作 java.io.OutputStreamWriter ,java.io.InputStreamReader

    package seday07; import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStr ...

  5. 自学_数据库<三>

    数据库 数据库概述 DBMS(DataBase Management System,数据库管理系统)和数据库.平时谈到"数据库"可能有两种含义:MSSQLServer.Oracle ...

  6. javascript模块化开发(二)

    模块化开发(一) ES6模块化 详解 ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict". 顶层的this指向undefined,即不应该在顶层代码 ...

  7. arcgis api 4.x for js 集成 Echarts4 实现模拟迁徙图效果(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 4.x for js:esri 官网 api,里面详细的介绍 arcgis api 4.x 各个类 ...

  8. 团队项目之Scrum2

    小组:BLACK PANDA 时间:2019.11.17 每天举行站立式会议 提供当天站立式会议照片一张 2 昨天已完成的工作 2 确定用户登录与注册和编辑页面的接口 前端方面:详细确定页面的功能,并 ...

  9. selinux disable

    临时关闭: [root@localhost ~]# getenforceEnforcing [root@localhost ~]# setenforce 0[root@localhost ~]# ge ...

  10. 41-data-packed volume container

    在上一节的例子中 volume container 的数据归根到底还是在 host 里,有没有办法将数据完全放到 volume container 中,同时又能与其他容器共享呢? 当然可以,通常我们称 ...