Python进阶(四)----生成器、列表推导式、生成器推导式、匿名函数和内置函数
Python进阶(四)----生成器、列表推导式、生成器推导式、匿名函数和内置函数
一丶生成器
本质:
就是迭代器
生成器产生的方式:
1.生成器函数 👇
2.生成器表达式 👇
3.python内置函数或者模块提供(其实1,3两种本质上差不多,都是通过函数的形式生成,只不过1是自己写的生成器函数,3是python提供的生成器函数 如: map() filter() zip()等等)
生成器与迭代器的区别:
生成器是我们自己用python代码构建的.迭代器可以使用iter() , __ iter __()进行取值
二丶生成器函数
####只要函数中出现了yiled ,那么就是一个生成器函数.(生成器)
## 一个next 对应一个yield
def func(): #当出现了yiled就是不再是函数了就是生成器函数
print(111)
print(111)
print(111)
print(111)
yield 2 # yield的作用是,yield后面的值 给了next取值
yield 3
yield 4
yield 5
ret=func() # 生成器对象 赋给变量ret
print(ret) # 生成器对象地址 <generator object func at 0x0000018ACC20EF68>
print(ret.__next__()) # ret执行__next__()方法 取值 2
print(ret.__next__()) # ret执行__next__()方法 取值 3
print(next(ret)) # ret执行__next__()方法 取值 4 next()方法的本质还是__next__()
print(next(ret)) # ret执行__next__()方法 取值 5
print(next(ret)) # 当 生成器对象中没有值可以取的时候就会报错---> StopIteration
三丶yiled与return的区别
return:
结束函数,给函数的执行者返回值,多个值通过元组返回,
yiled:
不结束函数 ,(暂停函数) . 对应着给next返回值 , 多个值通过元组返回
# return
def func():
return 1,2,3,4
print(func())
# yield
def func():
yield 1,2,3,4 # yield后面跟一个列表就返回一个列表,返回多个值就是返回一个元组
print(func().__next__())
四丶send(了解)
# next只能获取yield生成的值,但是不能传递值。
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield
print(f'{name} start to eat {food}')
dog = gen('alex')
next(dog)
next(dog)
next(dog)
# 而使用send这个方法是可以的。
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield 222
print(f'{name} start to eat {food}')
dog = gen('alex')
next(dog) # 第一次必须用next让指针停留在第一个yield后面
# 与next一样,可以获取到yield的值
ret = dog.send('骨头')
print(ret)
def gen(name):
print(f'{name} ready to eat')
while 1:
food = yield
print(f'{name} start to eat {food}')
dog = gen('alex')
next(dog)
# 还可以给上一个yield发送值
dog.send('骨头')
dog.send('狗粮')
dog.send('香肠')
############# 此处, 先看看, 之后会补充含义
#send和next()区别:
# 相同点:
# send 和 next()都可以让生成器对应的yield向下执行一次。
# 都可以获取到yield生成的值。
# 不同点:
# 第一次获取yield值只能用next不能用send(可以用send(None))。
# send可以给上一个yield置传递值。
五丶生成器的应用
##生成器应用 ,现在你需要一个服装工厂给你加工2000件衣服,
###可迭代对象
#老板很实在,一下给你准备好了2000件衣服
def func()
li=[]
for i in range(1,2001):
li.append(f'{i}件衣服')
return li
print(func()) # 老板的工厂中一半的场地都用来堆积2000衣服
# 总结, 加工2000个衣服, 假如说加工一件1秒, 你现在需要2000秒才能加工完成. 而且加工完的衣服必须有地方放置. 耗时耗空间. 但是比较很直观,2000个衣服就在工厂里囤放. 换到程序角度来说: 你需要2000条数据,你的内存中就存放了2000个数据. 不管你用多少,这2000条数据就会在内存是实实在在的占2000个位置. so 占内存大.
###生成器
#加工厂老板,给你准备好了加工衣服的传送带, 夸张一些加工一件衣服1秒.
def func(): #生成器函数, 相当于创建一个加工流水线
for i in range(1,2001):
yield print(f'{i}件衣服') #yield返回数据, 相当于把加工的衣服给来拿衣服的你
gen_obj = func() #把生成器给了一个变量, 确保每次来加工时,都是这个流水线(预定)
###需求: 现在你需要200件衣服,老板立马给你制作了200件衣服 ,剩下的1800件还在待加工的状态.
for i in range(200): # 你拿了200件 ,执行了200次拿的动作
gen_obj.__next__() # 在当前的这个流水线(当前的这个生成器),每次拿一件(每次取一个数据)
###需求: 现在你需要400件衣服,老板立马从剩余的1800件衣服中又制作了400件衣服给你,现在这个流水线还剩1200
for l in range(400): # 老板从你预定的流水线继续加工400件
next(gen_obj) # 还是在当前的这个流水线(当前的这个生成器),每次拿一件(每次取一个数据)
# 总结, 你预定了2000件衣服, 老板没有给你一起直接加工出来,每当你来拿衣服的时候你需要多少个,老板给你咔咔咔把你需要多少个衣服加工出来. 优势:1.对于老板的工厂来说,不占地方, (对于程序来说,不占内存,需要多少条,就生成多少条,内存中就占这么多,并且一点数据取出来(next)就销毁.) 2.对加衣服的你也没有影响.(不影响本身程序的调用)
##创建200个生成器函数 --->相当于创建了200流水线
for i in range(200): # 生成200个生成器函数
print(func().__next__(),type(func())) # 所以每次打印的都是 1
六丶yiled与yiled from
##yield
def func():
li=[1,2,3,4]
yield li # yield 返回一个值 , 若是yield后跟多个值,就以元组的形式返回
ret =func()
print(next(ret)) # 返回一个列表的值(只能得到一个值,next只接一次,不管你是元组 或 列表都是一个值返回)
print(next(ret)) # 报错 StopIteration
##yield from 可以把 后面的可迭代的对象进行拆分,依次给next取值.
def func():
li=[1,2,3,4]
yield from li # yield from 把可迭代对象拆分, 简化for循环,
'''
#表面现象
yield 1
yield 2
yield 3
yield 4
'''
ret =func()
print(next(ret)) # 1
print(next(ret)) # 2
print(next(ret)) # 3
print(next(ret)) # 4
#### yield 与yield from 对比 ####
# yield : 对应next ,给next 返回值
# yield from 将一个可迭代对象的每一个元素返回给next
# yield from 节省代码 ,提升效率
七丶列表推导式,生成器表达式(字典的推导式,集合推导式)
列表推导式:
一行代码构建一个有规律比较复杂的列表。(👇看代码.不废话)
####两种构建方式:
# 1.循环模式: [变量(加工后的变量) for 变量 in iterable]
# 2.筛选模式: [变量(加工后的变量) for 变量 in iterable if 条件]
######循环模式
##需求:循环 100以内的所有的值
#平常做法
li=[]
for i in range(1,101):
li.append(i)
print(li)
#列表推导式
print([i for i in range(1,101)])
######筛选模式 复杂程度不能超过3级
##案例1:三十以内可以被2整除的数。
print([i for i in range(1,31) if i%2==0])
#案例2: 找到嵌套列表中名字含有两个‘e’的所有名字(有难度)
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
##普通做法
li=[]
for el in names:
for el2 in el:
if el2.count('e')>=2:
li.append(el2)
print(li)
##列表推导式
print([name for el in names for name in el if name.count('e')>=2])
####列表推导式的优缺点
#优点:简单 快捷
#缺点:可读性不高,不好拍错
# 慎用,不用入迷
生成器表达式:
一行代码构建一个生成器。(👇看代码.不废话)
####两种构建方式:
# 1.循环模式: (变量(加工后的变量) for 变量 in iterable)
# 2.筛选模式: (变量(加工后的变量) for 变量 in iterable if 条件)
####循环模式
obj=(i for i in range(10))
print(obj) #<generator object <genexpr> at 0x000001972E9CEF68>
#如何触发生成器(迭代器 )取值?
# 1. next() , __next__() 逐个取值
# 2 . for 循环 遍历取值 哪个简单不用多说了吧
# 3 . list
for i in obj:
print(i)
####筛选模式
obj=(i for i in range(10) if x%2==0)
print(obj) #<generator object <genexpr> at 0x000001999105FF68>
字典的推导式: (创建模式同上👆,一行解决)
####两种构建方式:
# 1.循环模式: {变量(加工后的变量) for 变量 in iterable}
# 2.筛选模式: {变量(加工后的变量) for 变量 in iterable if 条件}
li= ['小潘', '第三部','金馆长', '宋老板']
#普通创建字典
dic={}
for k,i in enumerate(li):
dic[k]=i
print(dic)
#字典推导式
print({k:i for k,i in enumerate(li)})
集合推导式:(创建模式同上👆,一行解决)
####两种构建方式:
# 1.循环模式: {变量(加工后的变量) for 变量 in iterable}
# 2.筛选模式: {变量(加工后的变量) for 变量 in iterable if 条件}
#集合推导式
print({i for i in range(101)})
八丶内置函数
什么是内置函数:
由python解释器提供的一些特别的方法,目的提高开发效率
内置函数的数量:
目前:内置函数 68种
👇看代码吧:
# -*- coding: utf-8 -*-
# Author : Ds
#eval() 剥去字符串外衣 执行代码
s1='1+3'
ret=eval(s1) #去除两端字符,数字相加得到结果
print(ret)
#exce() 也是执行代码流,
s3='''
for i in range(10):
print(i)
'''
exec(s3) # 执行for循环
##建议👉: 不要不轻易使用这个两个内置函数. 都是会将代码执行,
#假如给了一个字符串的病毒,使用这两个方法任意执行.你的电脑都会中毒
#hash() 得到一个哈希值
print(hash(123)) # 数字的哈希值还是数字
print(hash('abc'))
print(hash('abcdkjahfduai'))
#help()查看方法,
print(help(str.upper()))
#callable() 判断是不是一个可调用的对象
# 如果返回 True,object 仍然可能调用失败;但如果返回 False,调用对象 object 绝对不会成功。
def abc():
pass
a=123
b='123'
print(callable(abc),dir(abc)) # '__call__'
print(callable(a))
print(callable(b))
#bin() oct() hex()
print(bin(100)) # 将十进制转化成二进制。 逢2进一
print(oct(10)) # 将十进制转化成八进制字符串并返回。 逢8进一
print(hex(17)) # 将十进制转化成十六进制字符串并返回。 逢16进一
# 二进制
# 只有 0 1 两个数字, 逢2进一
#八进制
# 0 - 7 , 逢8进一
#十六进制
#0 - 9 , a-f表示 10 -15 逢16进一
#divmod() 计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b) 分页用到
print(divmod(10, 3))
#round()保留小数位 四舍五入
print(round(3.123))
# pow() x**y x的y次幂
print(pow(2,3))
#ord() 输入字符寻找其在unicode的位置。
print(ord('a'))
print(ord('中'))
# chr() 输入位置数字找出其对应的字符
print(chr(98)) #
print(chr(20104)) # 予
#repr() 原形毕露 保留字符串格式
print('不打广告')
print(repr('不打广告'))
msg = '我叫%r' %('不打广告')
print(msg)
#all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE
#any() 函数用于判断给定的可迭代参数 iterable 是否全部为 False,
# 0,'',[],{},set(),(),None 都是False
l1 = [1, 'fgdsa', [], {1: 2}]
l2 = [0, '', [], {}]
print(all(l1)) # 判断可迭代对象元素全部都为True,返回True
print(any(l2)) # 判断可迭代对象元素只要有一个True返回True
九丶匿名函数
定义:
没有名字的函数 ,lambda表达式 ,匿名函数只能构建简单的函数 ,
#普通模式, 定义函数
def func(a,b):
return a+b
#匿名函数构建
#格式---> lambda关键字 传参 : 返回值
func2=lambda x,y:x+y
print(func2(1,2))
# 写匿名函数:接收一个可切片的数据,返回索引为 0与2的对应的元素(元组形式)。
#匿名函数最常用的就是与内置函数结合使用
#1.
func3=lambda argv : tuple(argv[0:3:2])
print(func3([1,2,3,4]))
#2.
func3=lambda x : (x[0],x[2])
print(func3('你好啊的'))
#3.
func4=lambda x,y : x if x>y else y
print(func4(1,2))
#4.
func4=lambda *args : max(args)
print(func4(1,2,3,4,5))