12.Python略有小成(生成器,推导式,内置函数,闭包)
python(生成器,推导式,内置函数,闭包)
一、生成器初始
- 生成器的本质就是迭代器,python社区中认为生成器与迭代器是一种
- 生成器与迭代器的唯一区别,生成器是我们自己用python代码构建成的
二、生成器产生方式
生成器函数
生成器表达式
-
python给你提供的一些内置函数,返回一个生成器
def func() print(111) yield 2 ret=func() # 生成器对象 print(ret) # <generator object func at 0x00000000021234f8> print(next(ret)) # 一个yield对应一个next # 只要函数中出现了yield他就不是函数,它是生成器函数
三、yield与return的区别
return 结束函数,给函数的执行者返回值(多个不同类型的值时通过元组形式返回值)
yield 不结束函数,对应着给next返回值
四、send
send和next()区别 :
相同点 : send 和 next()都可以让生成器对应的yield向下执行一次,都可以获取到yield生成的值
-
不同点 : 第一次获取yield值只能用next不能用send(可以用send(none),send可以给上一个yield置传递值
# 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('香肠')
五、yiled与yiled from
def func(): l1 = [1,2,3] yield l1 ret = func() print(next(ret)) # [1,2,3] print(next(ret)) # 报错 print(next(ret)) --------------------------------- def func(): l1 = [1,2,3] yield from l1 # li必须是可迭代对象 ret = func() print(next(ret)) # 1 print(next(ret)) # 2 print(next(ret)) # 3 --------------------------------- # yield对应next给next返回值 # yield from 将一个每一个可迭代对象的每一个元素返回给next,节省代码,提升效率,代替了for循环
六、列表推导式,生成器表达式
-
列表推导式 : 一行代码构建一个有规律比较复杂的列表
两种构建方式 :
-
循环模式 : [变量(加工后的变量) for 变量 in iterable]
print([i for i in range(1,11)]) --------------------------------- print([f"python{i}" for i in range(1,101)])
-
筛选模式 : [变量(加工后的变量) for 变量 in iterable if 条件]
print([i for i in range(1,101) if i%2==0]) --------------------------------- names = [['tom', 'billy', 'jefferson', 'andrew', 'wesley', 'steven', 'joe'], ['alice', 'jill', 'ana', 'wendy', 'jennifer', 'sherry', 'eva']] print([c for i in names for c in i if c.count("e")>=2])
列表推导式的优缺点 :
- 优点 : 简单,快捷
- 缺点 : 可读性不高,不好排错
-
-
生成器表达式 :
与列表推导式几乎一样,生成器时print打印的是地址,这是唯一不同点
-
循环模式
print((i for i in range(1,11))) # <generator object <genexpr> at 0x00000000021134f8>
-
筛选模式
print((i for i in range(1,101) if i%2==0)) # <generator object <genexpr> at 0x0000000001f134f8>
如何触发生成器(迭代器)取值
- next(生成器)
- for 内部用next(生成器)
- list(生成器)
-
七、内置函数 |
内置函数 : puthon解释器免费试用的内置函数功能68种,其中13种涉及面向对象.
-
eval:执行字符串类型的代码(解开并返回最终结果)
eval('2 + 2') # 4 n=81 eval("n + 4") # 85 eval('print(666)') # 666
-
exec:执行字符串类型的代码(只解开没有返回值)
s = ''' for i in [1,2,3]: print(i) ''' exec(s)
-
hash:获取一个对象(可哈希对象:int,str,bool,tuple)的哈希值。
print(hash(12322)) print(hash('123')) print(hash('arg')) print(hash('alex')) print(hash(true)) print(hash(false)) print(hash((1,2,3))) ''' -2996001552409009098 -4637515981888139739 1 2528502973977326415 '''
-
help:函数用于查看函数或模块用途的详细说明。
print(help(list)) print(help(str.split))
-
callable:函数用于检查一个对象是否是可调用的。如果返回true,object仍然可能调用失败;但如果返回false,调用对象ojbect绝对不会成功。
name = 'alex' def func(): pass print(callable(name)) # false print(callable(func)) # true
-
int:函数用于将一个字符串或数字转换为整型。
print(int()) # 0 print(int('12')) # 12 print(int(3.6)) # 3 print(int('0100',base=2)) # 将2进制的 0100 转化成十进制,结果为 4
-
float:函数用于将整数和字符串转换成浮点数。
print(float(3)) # 3.0
-
complex:函数用于创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。。
print(complex(1,2)) # (1+2j)
-
bin:将十进制转换成二进制并返回。
print(bin(10),type(bin(10))) # 0b1010 <class 'str'>
-
oct:将十进制转化成八进制字符串并返回。
print(oct(10),type(oct(10))) # 0o12 <class 'str'>
-
hex:将十进制转化成十六进制字符串并返回。
print(hex(10),type(hex(10))) # 0xa <class 'str'>
-
divmod:计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b)。
print(divmod(7,2)) # (3, 1)
-
round:保留浮点数的小数位数,默认保留整数。
print(round(7/3,2)) # 2.33 print(round(7/3)) # 2 print(round(3.32567,3)) # 3.326
-
pow:求x ** y次幂。(三个参数为x**y的结果对z取余)
print(pow(2,3)) # 两个参数为2**3次幂 print(pow(2,3,3)) # 三个参数为2**3次幂,对3取余。
-
ord : 输入字符找该字符编码的位置(在unicode内查找位置)
# ord 输入字符找该字符编码的位置 print(ord('a')) print(ord('中'))
-
chr : 输入位置数字找出其对应的字符(在unicode内查找位置)
# chr 输入位置数字找出其对应的字符 print(chr(97)) print(chr(20013))
-
repr:返回一个对象的string形式(原封不动)。
# %r 原封不动的写出来 name = 'taibai' print('我叫%r'%name) --------------------------------- print(repr('{"name":"alex"}')) print('{"name":"alex"}')
-
all:可迭代对象中,全都是true才是true
# all 可迭代对象中,全都是true才是true print(all([1,2,true,0]))
-
any:可迭代对象中,有一个true 就是true
# any 可迭代对象中,有一个true 就是true print(any([1,'',0]))
八、匿名函数
-
只能构建简单的函数,一句话函数
def func(x,y): return x+y print(func(1,2)) --------------------------------- func2=lambda x,y:x+y print(func(1,2))
九、内置函数 ||
-
print() 屏幕输出
''' 源码分析 def print(self, *args, sep=' ', end='\n', file=none): # known special case of print """ print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=false) file: 默认是输出到屏幕,如果设置为文件句柄,输出到文件 sep: 打印多个值之间的分隔符,默认为空格 end: 每一次打印的结尾,默认为换行符 flush: 立即把内容输出到流文件,不作缓存 """ ''' print(111,222,333,sep='*') # 111*222*333 print(111,end='') print(222) #两行的结果 111222 f = open('log','w',encoding='utf-8') print('写入文件',file=f,flush=true)
int() : 在此不过多说明
str() : 在此不过多说明
bool() : 在此不过多说明
set() : 在此不过多说明
-
list() 将一个可迭代对象转换成列表
l1 = list('abcd') print(l1) # ['a', 'b', 'c', 'd']
-
tuple() 将一个可迭代对象转换成元组
tu1 = tuple('abcd') print(tu1) # ('a', 'b', 'c', 'd')
-
dict() 通过相应的方式创建字典
list l1 = list('abcd') print(l1) # ['a', 'b', 'c', 'd'] tu1 = tuple('abcd') print(tu1) # ('a', 'b', 'c', 'd')
-
abs() 返回绝对值
i = -5 print(abs(i)) # 5
-
sum() 求和
print(sum([1,2,3])) print(sum((1,2,3),100))
-
min() 求最小值
print(min([1,2,3])) # 返回此序列最小值 ret = min([1,2,-5,],key=abs) # 按照绝对值的大小,返回此序列最小值 print(ret) # 加key是可以加函数名,min自动会获取传入函数中的参数的每个元素,然后通过你设定的返回值比较大小,返回最小的传入的那个参数。 print(min(1,2,-5,6,-3,key=lambda x:abs(x))) # 可以设置很多参数比较大小 dic = {'a':3,'b':2,'c':1} print(min(dic,key=lambda x:dic[x])) # x为dic的key,lambda的返回值(即dic的值进行比较)返回最小的值对应的键
max() 最大值与最小值用法相同
-
reversed() 将一个序列翻转, 返回翻转序列的迭代器 reversed
l = reversed('你好') # l 获取到的是一个生成器 print(list(l)) ret = reversed([1, 4, 3, 7, 9]) print(list(ret)) # [9, 7, 3, 4, 1]
-
bytes() 把字符串转换成bytes类型
s = '你好' bs = s.encode('utf-8') print(bs) 结果:b'\xe4\xbd\xa0\xe5\xa5\xbd\xe6\xad\xa6\xe5\xa4\xa7' s1 = bs.decode('utf-8') print(s1) 结果: 你好 s = '你好' bs = bytes(s,encoding='utf-8') print(bs) # 将字符串转换成字节 bs1 = str(bs,encoding='utf-8') print(bs1) # 将字节转换成字符串
-
zip() 拉链方法,函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,
然后返回由这些元祖组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回,
lst1 = [1,2,3] lst2 = ['a','b','c','d'] lst3 = (11,12,13,14,15) for i in zip(lst1,lst2,lst3): print(i) 结果: (1, 'a', 11) (2, 'b', 12) (3, 'c', 13)
-
sorted排序函数
语法:sorted(iterable,key=none,reverse=false) iterable : 可迭代对象 key: 排序规则(排序函数),在sorted内部会将可迭代对象中的每一个元素传递给这个函数的参数.根据函数运算的结果进行排序 # reverse :是否是倒叙,true 倒叙 false 正序 lst = [1,3,2,5,4] lst2 = sorted(lst) print(lst) #原列表不会改变 print(lst2) #返回的新列表是经过排序的 lst3 = sorted(lst,reverse=true) print(lst3) #倒叙 结果: [1, 3, 2, 5, 4] [1, 2, 3, 4, 5] [5, 4, 3, 2, 1] 字典使用sorted排序 dic = {1:'a',3:'c',2:'b'} print(sorted(dic)) # 字典排序返回的就是排序后的key 结果: [1,2,3] 和函数组合使用 # 定义一个列表,然后根据一元素的长度排序 lst = ['天龙八部','西游记','红楼梦','三国演义'] # 计算字符串的长度 def func(s): return len(s) print(sorted(lst,key=func)) # 结果: ['西游记', '红楼梦', '天龙八部', '三国演义'] #和lambda组合使用 lst = ['天龙八部','西游记','红楼梦','三国演义'] print(sorted(lst,key=lambda s:len(s))) 结果: ['西游记', '红楼梦', '天龙八部', '三国演义'] # 按照年龄对学生信息进行排序 lst = [{'id':1,'name':'alex','age':18}, {'id':2,'name':'wusir','age':17}, {'id':3,'name':'taibai','age':16},] print(sorted(lst,key=lambda e:e['age'])) 结果: [{'id': 3, 'name': 'taibai', 'age': 16}, {'id': 2, 'name': 'wusir', 'age': 17}, {'id': 1, 'name': 'alex', 'age': 18}]
-
filter筛选过滤
语法: filter(function,iterable) function: 用来筛选的函数,在filter中会自动的把iterable中的元素传递给function,然后根据function返回的true或者false来判断是否保留此项数据 iterable:可迭代对象 lst = [{'id':1,'name':'alex','age':18}, {'id':1,'name':'wusir','age':17}, {'id':1,'name':'taibai','age':16},] ls = filter(lambda e:e['age'] > 16,lst) print(list(ls)) 结果: [{'id': 1, 'name': 'alex', 'age': 18}, {'id': 1, 'name': 'wusir', 'age': 17}]
-
map映射函数
# 语法: map(function,iterable) 可以对可迭代对象中的每一个元素进映射,分别取执行function # 计算列表中每个元素的平方,返回新列表 lst = [1,2,3,4,5] def func(s): return s*s mp = map(func,lst) print(mp) print(list(mp)) # 改写成lambda lst = [1,2,3,4,5] print(list(map(lambda s:s*s,lst))) # 计算两个列表中相同位置的数据的和 lst1 = [1, 2, 3, 4, 5] lst2 = [2, 4, 6, 8, 10] print(list(map(lambda x, y: x+y, lst1, lst2))) 结果: [3, 6, 9, 12, 15]
-
reduce
from functools import reduce def func(x,y): return x + y # reduce 的使用方式: # reduce(函数名,可迭代对象) # 这两个参数必须都要有,缺一个不行 ret = reduce(func,[3,4,5,6,7]) print(ret) # 结果 25 reduce的作用是先把列表中的前俩个元素取出计算出一个值然后临时保存着, 接下来用这个临时保存的值和列表中第三个元素进行计算,求出一个新的值将最开始 临时保存的值覆盖掉,然后在用这个新的临时值和列表中第四个元素计算.依次类推 注意:我们放进去的可迭代对象没有更改 以上这个例子我们使用sum就可以完全的实现了.我现在有[1,2,3,4]想让列表中的数变成1234,就要用到reduce了. 普通函数版 from functools import reduce def func(x,y): return x * 10 + y # 第一次的时候 x是1 y是2 x乘以10就是10,然后加上y也就是2最终结果是12然后临时存储起来了 # 第二次的时候x是临时存储的值12 x乘以10就是 120 然后加上y也就是3最终结果是123临时存储起来了 # 第三次的时候x是临时存储的值123 x乘以10就是 1230 然后加上y也就是4最终结果是1234然后返回了 l = reduce(func,[1,2,3,4]) print(l) 匿名函数版 l = reduce(lambda x,y:x*10+y,[1,2,3,4]) print(l) 在python2.x版本中recude是直接 import就可以的, python3.x版本中需要从functools这个包中导入 龟叔本打算将 lambda 和 reduce 都从全局名字空间都移除, 舆论说龟叔不喜欢lambda 和 reduce 最后lambda没删除是因为和一个人写信写了好多封,进行交流然后把lambda保住了.
十、闭包
- 闭包形成的先决条件 :
- 闭包存在于嵌套函数中
- 内层函数对外层函数非全局变量引用(改变)
- 函数名逐层韩慧直至返回到最外层
闭包函数的特性 : 闭包函数的空间不会随着函数的结束而消失(被引用的可变数据类型不会消失)
-
判断一个函数是不是一个闭包 :
def make_averager(): series = [] def averager(new_value): series.append(new_value) total = sum(series) return total/len(series) return averager avg = make_averager() # 函数名.__code__.co_freevars 查看函数的*变量 print(avg.__code__.co_freevars) # ('series',)
- 闭包的应用 :
- 保证数据的安全,可以保存一些非全局变量但是不易被销毁、改变的数据。
- 装饰器的本质就是闭包