python 高阶函数 装饰器 语法糖
#############################高阶函数map########################## # #map()函数接收两个参数,一个是函数,一个是Iterable # #map将传入的函数依次作用到序列的每个元素, # # 并把结果作为新的Iterator返回。 # # 结果r是一个Iterator,Iterator是惰性序列, # # 因此通过list()函数让它把整个序列都计算出来并返回一个list def func(x): return x*x r = map(func,[1,2,3,4,5,6]) li = list(r) print(li,r) #[1, 4, 9, 16, 25, 36] <map object at 0x00000222A4118710> print(list(map(str, [1, 2, "3", "abc", 5, 6, 7, 8, 9]))) #list这里是使map出来的Iterator变成列表并返回一个列表,需要用变量接的,注意不能直接print(list) #['1', '2', '3', 'abc', '5', '6', '7', '8', '9']把列表中的数字转化成字符串
#将两个列表中对应位置的元素相加组成新的列表 l1 = [1,3,5,7,9] l2 = [2,4,6,8,10] ret1 = map(lambda x,y:x+y,l1,l2) print(list(ret1))
##################################高阶函数reduce######################## # reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数, # reduce把结果继续和序列的下一个元素做累积计算,其效果就是 # reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) from functools import reduce def add(x, y): return x*10 + y ret = reduce(add, [1,3,5,7,9]) print(ret) #13579 变为整数 from functools import reduce DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} #常量使用大写字母 def str2int(s): def fn(x, y): return x * 10 + y def char2num(s): #挺有意思,char to(2) num,字符串转数字 return DIGITS[s] #字典中键对应的值 return reduce(fn, map(char2num, s)) #map把字符串转化成整型的Iterator,fn又把Iterator转化成一个整数 print(str2int("123456")) #123456 # lambda只是一个表达式,函数体比def简单很多。 # lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去 # lambda表达式是起到一个函数速写的作用。允许在代码内嵌入一个函数的定义。 # f = lambda x,y,z:x+y+z #冒号前边的是形参,后边的是返回值的表达式 # print(f(1,2,3)) # #6 # #如上面的例子使用lambda写的话 from functools import reduce DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} def char2num(s): return DIGITS[s] def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))
#####################filter()函数用于过滤序列################ # 和map()类似,filter()也接收一个函数和一个序列。 # 和map()不同的是,filter()把传入的函数依次作用于每个元素, # 然后根据返回值是True还是False决定保留还是丢弃该元素 def is_odd(n): return n % 2 == 1 print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))) #[1, 5, 9, 15]
####计算素数 #先构造一个从3开始的奇数序列 def _odd_iter(): n = 1 while True: n = n + 2 yield n #注意这是一个生成器,并且是一个无限序列。 #然后定义一个筛选函数: def _not_divisible(n): return lambda x: x % n > 0 # 最后,定义一个生成器,不断返回下一个素数: def primes(): yield 2 it = _odd_iter() # 初始序列 it = [3,5,7,9,11,13,15,17,……] while True: n = next(it) # 返回序列的第一个数 此时n=3 yield n it = filter(_not_divisible(n), it) # 构造新序列 _not_divisible(3) it中的每项作为x,筛选出x%3>0,这样就把3的倍数除去了,我在这个参数传递上花了很长时间才弄懂 # 这个生成器先返回第一个素数2,然后,利用filter()不断产生筛选后的新的序列。 # 由于primes()也是一个无限序列,所以调用时需要设置一个退出循环的条件: # 打印1000以内的素数: for n in primes(): if n < 1000: print(n) else: break
#####*******************sorted()排序***************#### #之前我们已经学过在列表中有sort方法 li = [1,5,3,8] li.sort() #[1, 3, 5, 8] 升序排列 li.sort(reverse=True) #[8, 5, 3, 1]降序排列 li.reverse() #[8, 3, 5, 1] 反向排序 ##sorted()函数是python内置的,也是用来排序的 sorted([36,5,-12,9,-21]) #[-21, -12, 5, 9, 36]升序 sorted([36,5,-12,9,-21],key=abs) #sorted()是高阶函数,可以接收一个key函数,这里的key=abs表示的是取绝对值,列表中的元素被abs函数作用后,再把原来的元素做升序排列 #[5, 9, -12, -21, 36] sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower) #str.lower函数使得列表中的字符串变为小写后(注意lower后面不要加括号),然后以首字母进行升序排列,同sort进行降序排列只要在后面加一个reverse=True就可以了 #['about', 'bob', 'Credit', 'Zoo'] ret = sorted(['bob', 'about', 'Zoo', 'Credit'],key=str.lower,reverse=True ) #['Zoo', 'Credit', 'bob', 'about']
dic = {"a":3,"b":2,"c":1} print(min(dic,key=lambda x:dic[x])) #对字典进行迭代时,迭代的元素是键,而不应当认为是键值对.如 for i in dic 这里的i代表的就是键.同样的字典作为可迭代对象作用于函数中,函数作用的也是字典的键 #c print(sorted(dic,key=lambda x:dic[x])) #['c', 'b', 'a']
#以列表中元组的最后一个元素进行排序 students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] print(sorted(students,key=lambda x:x[2])) # #[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] #以列表中字典的值进行排序 students = [{'john': 15}, {'jane':12,}, {'dave':10,}] print(sorted(students,key=lambda x:x.copy().popitem()[1])) #因为字典中只有一个键值对,我们想通过字典而其键不同找到不同的值,可以考虑popitem(),popitem()随机删除字典中的一个键值对,并以元组的形式返回删除的键值对的键和值,因为字典中只有一个键值对所以通过popitem()再结合元组索引就可以找到字典的值,而我们要求字典不能改变所以通过copy()再复制一份 # [{'dave': 10}, {'jane': 12}, {'john': 15}]
students = [{'john': 15}, {'jane':12,}, {'dave':10,}] print(sorted(students,key=lambda x:list(students[students.index[x]].values())[0])) #使用values也可以 #[{'john': 15}, {'jane': 12}, {'dave': 10}]
###*******************偏函数******************* import functools int2 = functools.partial(int,base=2) print(int2("101111")) # ==>int("101111",base=2),把字符串"101111"当做2进制,转化成10进制 #47 #创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数 int2 = functools.partial(int, base=2) ==> kw = { 'base': 2 } # ==> int('10010', **kw) max2 = functools.partial(max, 10) #10作为*args的一部分自动加到左边,也就是 max2(5, 6, 7) ==> args = (10, 5, 6, 7) # ==> max(*args)
语法糖对于计算机的运行并没有任何的好处,但是对于程序员的好处是很大的,方便我们写代码,所以称为糖
#******************************装饰器************************* # 装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。 # 装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景 import time def func1(): print('in func1') def timer(func): def inner(): start = time.time() func() #这里的func取得是形参,形参给的是func1,所以这里执行的是func1() print(time.time() - start) return inner func1 = timer(func1) #func1作为参数传递到timer函数中,timer函数返回一个inner的返回值赋值给func1,func1()也即inner() func1() #timer这个函数是用来计算别的函数(形参为函数名)的运行时间
#********装饰器语法糖****** import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) 除了这条语句,其他的语句都一样,而@timer 就相当于 timer(func1)语句, #这个@timer语句相当于把timer函数和与它相邻的下一个函数以func1 = timer(func1)这样的形式关联起来 def func1(): print('in func1') time.sleep(1) #延时1s def func2(): print('in func2') time.sleep(2) #延时2s func1() func2() # in func1 # 1.0009326934814453 输出结果是1s多,很明显func1函数扩展了计时功能 # in func2
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> func1 = timer(func1) 除了这条语句,其他的语句都一样,而@timer 就相当于 timer(func1)语句, #这个@timer语句相当于把timer函数和与它相邻的下一个函数以func1 = timer(func1)这样的形式关联起来 def func2(): print('in func2') time.sleep(2) #延时2s def func1(): print('in func1') time.sleep(1) #延时1s func1() func2() # in func1 # in func2 # 2.0009799003601074 #这次因为func2和timer相邻,所以fun2扩展了计时功能
#*********装饰带参数函数*********** import time def timer(func): def inner(a): #这个a是形参,funcl(1)中的实参首先传给他 start = time.time() func(a) #func(a)中的func本身就是以函数为变量的形参,运行时func值实际为funcl,而a作为形参同时作为变量a的值与上面一致是1 print(time.time() - start) return inner @timer def func1(a): #这个a也是形参,与上面两个保持一致 print(a) #这个a不是必须的,此处只是使用它打印 func1(1) #inner
from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方,这个是必要的,不然会出错 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) #查看函数注释的方法 print(index.__name__) #查看函数名的方法
import time def func1(): '''注释1''' print('in func1') def timer(func): def inner(): '''注释2''' start = time.time() func() print(time.time() - start) return inner func1 = timer(func1) print(func1.__name__) print(func1.__doc__) # in func1 # 0.0 # inner 不使用@wraps(func)这个东西时,会认为func1的名字的注释是inner的名字和注释 # 注释2
#******************装饰器的固定格式************ def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper *****************带参数的装饰器,带上标志可以灵活的决定是否使用装饰器************** def outer(flag): def timer(func): def inner(*args,**kwargs): if flag: print('''执行函数之前要做的''') re = func(*args,**kwargs) if flag: print('''执行函数之后要做的''') return re return inner return timer @outer(False) def func(): print(111) func() #******************多个装饰器装饰一个函数*************** def wrapper1(func): def inner(): print('wrapper1 ,before func') func() print('wrapper1 ,after func') return inner def wrapper2(func): def inner(): print('wrapper2 ,before func') func() print('wrapper2 ,after func') return inner @wrapper2 @wrapper1 def f(): print('in f') f()
##多个装饰器装饰一个函数详解
def wrapper1(fn): def inner(*args,**kwargs): print("我是wrapper1前面的") ret = fn(*args,**kwargs) print("我是wrapper1后面的") return ret return inner def wrapper2(fn): def inner(*args,**kwargs): print("我是wrapper2前面的") ret = fn(*args,**kwargs) print("我是wrapper2后面的") return ret return inner @wrapper1 # @wrapper1 可以看做是 wrapper2 = wrapper1(wrapper2) @wrapper2 # @wrapper2 可以看做是 func = wrapper2(func) 但却不能直接用这两个语句替换,应该使用func = wrapper1(wrapper2(func)) def func(): print("我是func") func() ''' 我是wrapper1前面的 我是wrapper2前面的 我是func 我是wrapper2后面的 我是wrapper1后面的 ''' def wrapper1(fn): def inner(*args,**kwargs): print("我是wrapper1前面的") ret = fn(*args,**kwargs) print("我是wrapper1后面的") return ret return inner def wrapper2(fn): def inner(*args,**kwargs): print("我是wrapper2前面的") ret = fn(*args,**kwargs) print("我是wrapper2后面的") return ret return inner def func(): print("我是func") func = wrapper1(wrapper2(func)) #即多个装饰器的实际语句是 func = wrapper1(wrapper2(wrapper3(...(wrapper100(func))))) func() ''' 我是wrapper1前面的 我是wrapper2前面的 我是func 我是wrapper2后面的 我是wrapper1后面的 '''
#*****最全的固定格式 from functools import wraps def wrapper_out(flag): def wrapper(fn): @wraps(fn) def inner(*args,**kwargs): if flag: #flag为真执行装饰器 '''函数执行前语句''' ret = fn(*args,**kwargs) '''函数执行后语句''' return ret else: #flag为假不执行装饰器 ret = fn(*args, **kwargs) return ret return inner return wrapper @wrapper_out(True) def func(*args,**kwargs): print("我是func")
func()
print(func.__name__,func.__doc__)
# 我是func
# func None