python中的推导式、生成器

文章目录

推导式

通过一行循环判断遍历出一些列数据的方法叫做推导式
推导式comprehensions(又称解析式),是Python的一种独有特性。
推导式是可以从一个数据序列构建另一个新的数据序列的结构体。 共有三种推导,在Python2和3中都有支持:
化简代码用的
推导式的核心为 for 循环。根据返回对象的不同,推导式可区分为列表推导式,字典推导式,集合推导式等。不同推导式在语法上基本一致。
实际上就是根据公式生成新的,想要的列表,集合,字典

语法:
val for val in iterable [if 条件表达式]

其中 if 条件判断根据需要,可有可无。

1.推导式基本语法

#老方法
lst = []
for i in range(1,51):
    lst.append(i)
print(lst)

#改写推导式
lst = [ i for i in range(1,51) ]
print(lst)

运行
运行

在这里插入图片描述

2.列表推导式

for前面是要获取的存在列表里面的数据

list1 = [i for i in range(1, 10) if i % 2 == 0]
print(list1)

[2, 4, 6, 8]

list2 = [i for i in range(0, 10, 2)]
print(list2)

[0, 2, 4, 6, 8]

运行
运行

#小练习

#1.[1,2,3,4,5] => [2,4,6,8,10]
lst = [ i*2 for i in range(1,6) ]
print(lst)

 
 
运行
运行

2.带有判断条件的推导式

“”“注意点:for后面紧跟的判断条件只能是单项分支.”“”
“”“[1,2,3,4,5,6,7,8,9,10] => [1,3,5,7,9 … ]”“”

lst = [1,2,3,4,5,6,7,8,9,10]
lst_new = []
for i in lst:
    if i % 2 == 1:
        lst_new.append(i)
print(lst_new)

#改写推导式
lst = [ i for i in lst if i % 2 == 1 ]
print(lst)

运行
运行

3.多循环推导式

lst1 = ["孙杰龙","陈露","曹静怡"]
lst2 = ["王志国","邓鹏","合理"]
lst_new = []
for i in lst1:
    for j in lst2:
        lst_new.append(i+"♡♢♤♠"+j)
print(lst_new)

#改写推导式
lst = [ i+“♡♢♤♠”+j for i in lst1 for j in lst2 ]
print(lst)

运行
运行

在这里插入图片描述

在这里插入图片描述

创建多个for循环的实现列表推导式: 等同于for循环嵌套

#创建列表:[(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

list1 = [(i, j) for i in range(1, 3) for j in range(3)]
print(list1)

[(1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

运行
运行

在这里插入图片描述

合并列表为字典:

list1 = ['name', 'age', 'gender']
list2 = ['Tom', 18, 'man']

d1 = { list1[i]: list2[i] for i in range(len(list2))}
print(d1)

{ ‘name’: ‘Tom’, ‘age’: 18, ‘gender’: ‘man’}

运行
运行

如果两个列表数据不同,按个数少的长度来统计,即len(最少数据的列表)

4.带有判断条件的多循环推导式

lst_new = []
for i in lst1:
    for j in lst2:
        if lst1.index(i) == lst2.index(j):
            lst_new.append(i+"♡♢♤♠"+j)
print(lst_new)

#改写推导式
lst = [i+“♡♢♤♠”+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]
print(lst)

在这里插入图片描述

5.求M,N中矩阵和元素的乘积

 # =>实现效果2   [[2, 4, 6], [12, 15, 18], [28, 32, 36]]
# M = [ [1,2,3],
#     [4,5,6],
#     [7,8,9]  ]

# N = [ [2,2,2],
# [3,3,3],
# [4,4,4] ]

M = [ [1,2,3] ,[4,5,6] , [7,8,9] ]
N = [ [2,2,2] ,[3,3,3] , [4,4,4] ]

lst = [[M[i][j] * N[i][j] for j in range(3)] for i in range(3)]
print(lst)

运行
运行

在这里插入图片描述

列表推导式练习
在这里插入图片描述

6.集合推导式

案例:
满足年龄在18到21,存款大于等于5000 小于等于5500的人,
开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)
把开卡的种类统计出来

lst = [
    {"name":"赵沈阳","age":18,"money":3000},
    {"name":"赵万里","age":19,"money":5200},
    {"name":"赵蜂拥","age":20,"money":100000},
    {"name":"赵世超","age":21,"money":1000},
    {"name":"王志国","age":18,"money":5500},
    {"name":"王永飞","age":99,"money":5500}
]
setvar = set()
for i in lst:
    print(i) # {'name': '赵沈阳', 'age': 18, 'money': 3000}
    if 18 <= i["age"] <= 21 and 5000 <= i["money"] <= 5500:
        res = "尊贵VIP卡老{}".format(i["name"][0])
    else:
        res = "抠脚大汉卡老{}".format(i["name"][0])
    # 添加到集合中
    setvar.add(res)
print(setvar)

#{ 三元运算符 + 推导式 }
setvar = { “尊贵VIP卡老{}”.format(i[“name”][0]) if 18 <= i[“age”] <= 21 and 5000 <= i[“money”] <= 5500 else “抠脚大汉卡老{}”.format(i[“name”][0]) for i in lst }
print(setvar)

运行
运行

在这里插入图片描述

7.字典推导式

一.enumerate

enumerate(iterable,[start=0])
功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
参数:
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
start: 可以选择开始的索引号(默认从0开始索引)
返回值:迭代器

#基本语法

from collections import Iterator,Iterable
lst =["王文","吕洞宾","何仙姑","铁拐李","张国老","曹国舅","蓝采和","韩湘子"]
it = enumerate(lst)
it = enumerate(lst,start=100)
print(isinstance(it,Iterator))

#next
print( next(it) )

# for + next (推荐,数据较大时使用。海量数据时不能一次性把数据都放到内存中)
for i in range(3):
print(next(it))

在这里插入图片描述

# for
for i in it:
    print(i)

 
 
  • 1
  • 2
  • 3

在这里插入图片描述

#dict 强转迭代器,这是一次性把数据全部转换成dict,数据较大时容易死机

print(dict(it))

 
 

在这里插入图片描述

在这里插入图片描述

#(1) 字典推导式 配合 enumerate 来实现

dic = {k:v for k,v in enumerate(lst,start=100)}
print(dic)

(100, ‘王文’)
(101, ‘吕洞宾’)
(102, ‘何仙姑’)
(103, ‘铁拐李’)
(104, ‘张国老’)
(105, ‘曹国舅’)
(106, ‘蓝采和’)
(107, ‘韩湘子’)

在这里插入图片描述
在这里插入图片描述

#(2) 使用dict强转迭代器,瞬间得到字典

dic = dict( enumerate(lst,start=100) )
print(dic)

 
 
二.zip

特点:按照索引配对
zip(iterable, … …)
功能: 将多个iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回 要是生成字典只能有两个iterable
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
返回: 迭代器

在这里插入图片描述

# 基本语法
# lst1 = ["孙开启","王永飞","于朝志"]
# lst2 = ["薛宇健","韩瑞晓","上朝气"]
# lst3 = ["刘文博","历史园","张光旭"]

# 在索引下标同时存在时,才会进行配对,否则舍弃.
lst1 = [“孙开启”,“王永飞”,“于朝志”]
lst2 = [“薛宇健”,“韩瑞晓”]
lst3 = [“刘文博”]

it = zip(lst1,lst2,lst3)
print(list(it))

运行
运行

在这里插入图片描述

两个容器才能用字典方法强转,否则报错
在这里插入图片描述

#(1) 字典推导式 配合 zip 来实现

lst_key = ["ww","axd","yyt"]
lst_val = ["王维","安晓东","杨元涛"]

#(‘ww’, ‘王维’), (‘axd’, ‘安晓东’), (‘yyt’, ‘杨元涛’)
dic = { k:v for k,v in zip(lst_key , lst_val) }
print(dic)

运行
运行

在这里插入图片描述

以最短可迭代数据为准,多的舍弃
在这里插入图片描述

#(2) 使用dict强转迭代器,瞬间得到字典

dic = dict( zip(lst_key , lst_val) )
print(dic)

 
 

在这里插入图片描述

生成器

理解生成器,最好的方法就是给他取个突出其本质的别名:生成数据的机器代码。

    生成器是一种用时间换空间的做法。比如,利用list列表储存全体正整数,无穷个正整数再大的内存也无法装得下,这个时候就可以使用生成器,实现用一段代码来储存全部正整数的作用

 
 

一,生成器的官方定义

    在Python中,一边循环一边计算的机制,称为生成器:generator。

 
 

(1).生成器表达式
生成器表达式返回一个生成器对象即generator object,需要用一个变量名来接收并绑定。

(2).生成器函数
含有 yield 关键字的函数,调用该函数时会返回一个生成器。

二,next()&next()和send()方法

1,__next__()&next()的区别
        __next__()是生成器对象的实例方法,next()是python的内置方法。他们实现的功能是一样的,只能对可迭代的对象使用。

2,next()和send()用以唤醒生成器
当生成器函数中执行yield时,程序会卡在yield的地方不执行,next()和send()的作用就是唤醒卡住的程序,让他继续执行。

3,send()方法的作用
send()作为生成器对象的实例方法,可以向生成器发送数据并唤醒生成器函数。一般send()方法要写在next()方法后面,当next()和send()写在一块时,相当于唤醒两次生成器。

生成器表达式无法像列表推导式那样直接输出,它和可迭代对象一样只能采用for循环调用next()函数,原因在于range返回的是一个可迭代对象,
列表推导式之所以能直接print就是因为 []将可迭代对象转为列表。

在这里插入图片描述

#生成器

#生成器本质是迭代器,允许自定义逻辑的迭代器

#迭代器和生成器区别:
迭代器本身是系统内置的.重写不了.
而生成器是用户自定义的,可以重写迭代逻辑

#生成器可以用两种方式创建:
(1)生成器表达式 (里面是推导式,外面用圆括号)
(2)生成器函数 (用def定义,里面含有yield)

三, 生成器表达式 (里面是推导式,外面用圆括号)

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

 
 
'
运行
运行

在这里插入图片描述

#判断类型

from collections import Iterator,Iterable
print(isinstance(gen,Iterator))

 
 

在这里插入图片描述

四, 生成器的调用

1.next 调用生成器
print(next(gen))
print(next(gen))

 
 
2.for + next 调用生成器
for i in range(3):
    print(next(gen))
3.for 调用生成器所有数据
for i in gen:
    print(i)

 
 
4.list强转生成器,瞬间得到所有数据
gen = ( i for i in range(10) )
print(list(gen))

#print(next(gen)) error # StopIteration 超出范围

运行
运行

五, 生成器函数

#yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
而return直接终止函数,每次重头调用.
yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用
携程之所以能在不同任务里面切换,依赖的就是yield,能记住这次任务中执行的位置和状态,CPU切换时从上次位置往下走

“”"

#(1) 基本语法

def mygen():
    print("111")
    yield 1

print(“222”)
yield 2

print(“333”)
yield 3

运行
运行

#初始化生成器函数 => 返回生成器对象 => 简称生成器
调用该函数的时候不会立即执行代码,而是返回了一个生成器对象;
当使用 next() (在 for 循环中会自动调用 next() ) 作用于返回的生成器对象时,函数 开始执行,在遇到 yield 的时候会『暂停』,并返回当前的迭代值;
当再次使用 next() 的时候,函数会从原来『暂停』的地方继续执行,直到遇到 yield语句,如果没有 yield 语句,则抛出异常;
gen = mygen()

# 第一次调用
res = next(gen)
print(res)
# 第二次调用
res = next(gen)
print(res)
# 第三次调用
res = next(gen)
print(res)
# 第四次调用

StopIteration error
res = next(gen)
print(res)

创建生成器方法:
(1)生成器表达式 (里面是推导式,外面用圆括号)
在这里插入图片描述

(2)生成器函数 (用def定义,里面含有yield)
在这里插入图片描述

调用方法:
1.使用生成器对象的实例方法 生成器.next()
2.使用Python内置方法 next(生成器)
在这里插入图片描述

# 第一次调用
print("111")  yield 1 保存当前第13行代码的状态,1返回,并且等待下一次调用
# 第二次调用
从上一次保存的位置13行往下走, print("222") yield 2 保存当前第16行代码的状态,2返回,并且等待下一次调用
# 第三次调用
从上一次保存的位置16行往下走, print("333") yield 3 保存当前第19行代码的状态,3返回,并且等待下一次调用
# 第四次调用
因为没有更多的yield 返回数据,所有停止迭代.出现报错异常.

 
 

#(2) 优化生成器代码
“”“生成器应用的场景是在大数据的范围中使用, 切记不可直接用for遍历所有,可能无法短时间内获取所有数据”“”
每次手动写yield 1…2…3…4…就太蠢了,需要优化

def mygen():
    for i in range(1,101):
        yield i

#初始化生成器函数 => 生成器
gen = mygen()
print(“<=====>”)
for i in range(30):
num = next(gen)
print(“我的球衣号码是{}”.format(num))

print(“<=====>”)

运行
运行

在这里插入图片描述

可以连续遍历:,号码从上次遍历结尾接着开始
for i in range(40):
num = next(gen)
print(“我的球衣号码是{}”.format(num))

#(3) send的使用方式 (给上一个yield发送数据)

#next和send区别:
next 只能取值
send 不但能取值,还能发送值,发送给yield
#send注意点:
第一个 send 不能给 yield 传值 默认只能写None
最后一个yield 接受不到send的发送值

def mygen():
    print("start")

res = yield “内部1”
print(res,“<内部>”)

res = yield “内部2”
print(res,“<内部>”)

res = yield “内部3”
print(res,“<内部>”)

<span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"end"</span><span class="token punctuation">)</span>

# 初始化生成器函数 => 生成器
gen = mygen()
# 第一次调用生成器
“”"
第一次调用生成器时,因为没有遇到yield保存的代码位置,
无法发送数据,默认第一次只能发送None
“”“

res = gen.send(None)
print(res,”<外部>")

# 第二次调用生成器
res = gen.send(“100”)
print(res,“<外部>”)

# 第三次调用生成器
res = gen.send(“200”)
print(res,“<外部>”)

# 第四次调用生成器
“”"
error
res = gen.send(“300”)
print(res,“<外部>”)
“”“

”“
使用send调用生成器,第一次发送时必须是None,因为还没有遇到yield保存的代码位置
res = gen.send(None) 走到mygen生成器函数中
print(“start”)
res = yield “内部1” 执行第80,保存退出,记录当前代码位置,“内部1” 返回
98行接受数据 res = “内部1” print(内部1,“<外部>”)

第二次调用生成器
res = gen.send(“100”)100这个数据发送给上一次代码保存的位置80行进行接受. => 导致 80行 res = 100
打印81print(100 ,“<内部>”)
执行83行 res = yield “内部2” 保存退出,记录当前代码位置,“内部2” 返回
执行102行 res = gen.send(“100”) => “内部2” print(“内部2”,“<外部>”)

依次类推 …
到第四次调用时, 因为没有更多的yield 返回数据,gen.send(300)无法接受到返回值,所以出现停止迭代 StopIteration的报错,程序终止;

send执行流程
在这里插入图片描述

send要想成功执行,第一次必须发送None,最后一次调用,要有对应层级的yield,也就是send个数少于等于yield个数

#(4) yield from 的使用
“”“将一个可迭代对象变成一个迭代器返回 “””

def mygen():
    lst = ["张磊","李亚峰","刘一峰","王同培"]
    yield from lst

#初始化生成器函数
gen = mygen()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
#print(next(gen)) # StopIteration

运行
运行

在这里插入图片描述

#(5) 斐波那契数列
使用生成器分段获取所有内容,而不是一股脑的把所有数据全部打印
1 1 2 3 5 8 13 21 34 …

def mygen(maxval):
    a,b = 0,1
    i = 0
    while i < maxval:
        # print(b) 
        yield b
        a,b = b,a+b
        i += 1
# mygen(10)
gen = mygen(10)

# 第一次获取
for i in range(3):
print(next(gen))

# 第二次获取
for i in range(5):
print(next(gen))

'
运行
运行

在这里插入图片描述
在这里插入图片描述

使用生成器,可以分段获取,不用全部打印

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值