一、高阶函数
1、接受一个或多个函数作为参数 2、输出一个函数
def counter(base): def inc(sep=1): nonlocal base base += sep return base return inc foo = counter(10) foo1 = counter(10) print(foo( )) print(foo1( ))
foo和foo1不一样,因为inc是调用counter时产生的一个变量,赋值即定义,是个新的,foo的引用对象在堆上,不被删掉,地址放在foo上了
3、自己实现一个sort
lst = [1,9,6,7,8,3,4,5,2] def sort(iterable,reverse=False): ret = [] for x in iterable: for i,y in enumerate(ret): if x > y: ret.insert(i,x) break else: ret.append(x) return ret print(sort(lst))
这是倒序的sort,改变lst,使用插入
lst = [1,9,6,7,8,3,4,5,2] def sort(iterable,reverse=False): ret = [] for x in iterable: for i,y in enumerate(ret): flag = x>y if reverse else x<y if flag: ret.insert(i,x) break else: ret.append(x) return ret print(sort(lst))
这是支持反转的sort
lst = [1,9,6,7,8,3,4,5,2] def sort(iterable,key=lambda a,b:a<b,reverse=False): ret =[] for x in iterable: for i,y in enumerate(ret): if comp(x,y,reverse): ret.insert(i,x) break else: ret.append(x) return ret print(sort(lst))
这是改版后的反转
4、filter函数(function,iterable) 1、过滤可迭代对象的元素,返回一个迭代器 2、function一个具有一个参数的函数,返回bool 3、例如,过滤出数列中能被3整除的数字 a = filter(lambda x:x%3==0,[1,9,55,150,-3,78,28,123]) next(a)这是个迭代器,得到的是要的元素
5、map函数(function,*iterables) 1、对多个可迭代对象的元素按照指定的函数进行映射,返回一个迭代器 2、list(map(lambda x:2*x+1,range(5))) 3、dict(map(lambda x:(x%5,x),range(500))) 4、都是迭代器,按要求重新生成一个值出来,映射值,就是2*x+1
6、sort、map、filter都是高阶函数,他们的参数都是函数
二、柯里化
1、原来接受两个参数的函数,变成新的接受一个参数的函数的过程 2、 def add(x): def add1(y): return x+y return add1 foo = add(4) foo(5)
三、装饰器
1、业务函数内部添加其他语句,耦合度太高,而且属于侵入式代码
2、def add(x,y): print(add.__name__,x,y) 双下划线,和name,输出的就是函数的name
3、业务函数是装饰器的参数
def add(x,y,*args,z,**kwargs): return x+y+z def logger(fn,*args,**kwargs): ret = fn(*args,**kwargs) return ret print(logger(add,4,5,z=6))
4、装饰器如下,@logger为缩写----add=logger(add)
def logger(fn): def _logger(*args,**kwargs): return fn(*args,**kwargs) return _logger @logger def add(x,y,*args,z=1,**kwargs): sum = x+y+z for i in args: sum += i for j in kwargs.values(): sum += j return sum print(add(1,2,3,4,z=5,k=8,m=9,l=10))
5、文档字符串
1、在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号 2、首字母大写,第一行写概述,空一行写第一行 3、fn.__name__,fn.__doc__ 4、装饰器后,name和doc都产生了变化,所以要修改
5、装饰器怎么打印业务函数的name和doc属性等 def copy_properties(src,dst): src.__name__ = dst.__name__ src.__doc__ = dst.__doc__ def logger(fn): def _logger(*args): ''' This is a wrapper ''' return fn(*args) copy_properties(_logger,fn) return _logger @logger def add(x,y): ''' This is a function of addition return int x int y int ''' return x+y print(add(4,9)) print(add.__name__,add.__doc__,sep="\n")
三、树的遍历
1、广度优先、层序遍历 2、深度优先:前序遍历,中序遍历,后序遍历 DLR、LDR、LRD 3、必须先左后右,根据根来判断先中后
四、堆排序
1、堆是一个完全二叉树 2、每个非叶子结点,都大于等于其左右孩子结点的值,是大顶堆 3、每个非叶子结点,都小于等于其左右孩子结点的值,是小顶堆 4、根结点一定是大顶堆的最大值,是小顶堆的最小值 5、构建大顶堆 1、度数为2的结点,如果它的左右孩子结点的最大值比它大,则交换 2、度数为1的结点,如果它的左孩子结点值大于它,则交换 3、如果结点A被交换到新的位置,则还需要重复上面的1、2交换 6、构建大顶堆起点选择 1、从完全二叉树的最后一个结点的父结点开始 2、结点为n,则n//2等于那个起始点 3、从起始点开始,向左找同层结点,到头后,到上层的最右边结点开始继续向左逐个查找,直到根结点 4、最大的一定在第一层,第二层一定有一个次大的
五、函数注解:
1、inspect模块----提供获取对象信息的函数,可以检查函数、类、类型检查
2、 import inspect def add(x:int,y:int,*args,**kwargs): return x+y sig = inspect.signature(add) print(add.__annotations__) # 这是个无序字典,信息 print(sig) # 函数的参数信息、签名 print('params:',sig.parameters) # 取参数,这是个有序字典,'x':'x:int' print('return:',sig.return_annotation) # 返回值的注解是什么 print(sig.parameters['x']) # 取变量名的value,(参数:注解) print(sig.parameters['y'].annotation) # 取变量名的value的注解,类型 print(sig.parameters['args']) # 取args的value, print(sig.parameters['args'].annotation) # args的类型为空,因为接收的东西不知道 print(sig.parameters['kwargs']) print(sig.parameters['kwargs'].annotation)
3、inspect.isfunction(add),是否是参数 inspect.ismethod(add),是否是类的方法 inspect.isgenerator(add),是否是生成器 inspect.isclass(add),是否是类 inpect.ismodule(inspect),是否是模块 inspect.isbuiltin(print),是否是内建对象 查询inspect的帮助获取其他is函数
4、Parameter对象----参数
1、保存在元组中,是只读的 2、name,参数的名字 3、annotation,参数的注解,可以没有 4、default,参数的缺省值,可能没有定义 5、empty,特殊的类,标记default属性或者注释annotation属性的空值 6、kind,实参如何绑定到形参 1、Positional_OR_Keyword,值可以作为关键字或者位置参数提供 2、Var_Positional,可变位置参数,对应*args 3、Keyword_Only 4、Var_Keyword
六、偏函数
1、把函数部分的参数固定下来,返回新函数 2、functools的partial用法,固定x参数,下面的传参要注意 import functools def add(x,y[,*args])->int: ret = x+y return ret newadd = functools.partial(add,6[,1,2,3,4,5])-----拿走了,add(6) print(newadd(7))------add(6)(7) args收集多余的,这样恒定得7
七、缓存模块
1、@functools.lru_cache(maxsize=128,typed=False) 2、Least-recently-used装饰器。lru,最近最少使用 3、如果maxsize设置为None,则禁用lru功能,并且无线缓存增长,当maxsize是2的幂时,lru功能执行的最好 4、如果typed设置为True,则不同类型的函数参数将单独缓存 5、下面程序,两个9,第一个睡3秒,下一个瞬间出来
import functools import time @functools.lru_cache() def add(x,y=5): time.sleep(3) return x+y print(add(4)) print(add(4))
6、lru_cache装饰器应用
前提
1、同样的函数参数,一定得到同样结果 2、函数执行时间很长,且多次执行本质是函数调用的参数---》返回值 3、缺点: 1、不支持过期,key无法过期,失效 2、不支持清除操作 3、不支持分布式,是一个单机的缓存 4、试用场景:单机上空间换时间
习题:
1、带参装饰器
def copy_properties(src): def _copy(dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ return dst return _copy def logger(fn): @copy_properties(fn) # wrapper = copy_properties(fn)(wrapper) def wrapper(*args,**kwargs): """ This is a wrapper """ ret = fn(*args,**kwargs) return ret return wrapper @logger def add(x,y): """ This is a function of addition """ return x+y print(add(4,5)) print(add.__name__,add.__doc__,sep="\n")
# t可以多个,下面直接用logger(t1,t2),下面@logger(1,2)
import datetime import time def logger(t): def _logger(fn): def wrap(*args,**kwargs): start = datetime.datetime.now() time.sleep(3) ret = fn(*args,**kwargs) duration = (datetime.datetime.now()-start).total_seconds() if duration > t: print("function {} took {}s.".format(fn.__name__,duration)) return ret return wrap return _logger @logger(3) def add(x,y): time.sleep(3) return x+y print(add(4,5))
2、字典扁平化
# 字典扁平化----> a.b:1,a.c2,d.e:3,d.f.g:4 org_dict = {'a':{'b':1,'c':2},'d':{'e':3,'f':{'g':4}}} def tree_dict(src,prefix=''): target = {} for k,v in src.items(): if isinstance(v,(dict,list,set,tuple)): tree_dict(v,prefix+k+'.') else: target[prefix+k] = v return target foo = tree_dict(org_dict) print(foo)
3、堆排序
import math def print_tree(array): index = 1 depth = math.ceil(math.log2(len(array))) # 因为列表前面补了0 sep = ' ' for i in range(depth): offset = 2 ** i print(sep*(2**(depth - i - 1) - 1),end='') line = array[index:index + offset] for j, x in enumerate(line): print("{:>{}}".format(x,len(sep)),end='') interval = 0 if i == 0 else 2 ** (depth-i) - 1 if j < len(line) - 1: print(sep * interval,end='') index += offset print() origin = [0,50,10,90,30,70,40,80,60,20] total = len(origin) - 1 # 初始待排序个数,前面加0了 print(origin) print_tree(origin) print("="*50) def heap_adjust(n,i,array:list): while 2 * i <= n: lchild_index = 2*i max_childindex = lchild_index if n > lchild_index and array[lchild_index+1] > array[lchild_index]: # n>2i说明还有右孩子 max_childindex = lchild_index + 1 if array[max_childindex] > array[i]: array[i],array[max_childindex] = array[max_childindex],array[i] i = max_childindex else: break # 构建大顶堆 def max_heap(total,array:list): for i in range(total//2,0,-1): heap_adjust(total,i,array) return array print_tree(max_heap(total,origin)) print("="*50) # 排序 def sort(total,array:list): while total > 1: array[1],array[total] = array[total],array[1] total -= 1 if total == 2 and array[total] >= array[total-1]: break heap_adjust(total,1,array) return array print_tree(sort(total,origin)) print(origin)
4、inspect应用
import inspect from functools import wraps def check(fn): @wraps(fn) def wrapper(*args,**kwargs): # 实参检查 print(args,kwargs) #解构,**kwargs不行,字典解开是x=1这种,赋值即定义,没有这个x变量 sig = inspect.signature(fn) params = sig.parameters # 有序字典,只读的 for _,v in sig.parameters.items(): print(v.name,v) # 位置参数处理 paramlist = list(params.keys()) for i,v in enumerate(args): k = paramlist[i] if isinstance(v,params[k].annotation): print(v,"is",params[k].annotation) else: errstr = "{}{}{}".format(v, 'is not', params[k].annotation) print(errstr) raise TypeError() # 关键字传参处理 for k,v in kwargs.items(): if isinstance(v,params[k].annotation): print(v,"is",params[k].annotation) else: errstr = "{}{}{}".format(v,'is not',params[k].annotation) print(errstr) raise TypeError() ret = fn(*args,**kwargs) return ret return wrapper @check def add(x:int,y:int=7): return x+y print(add(7))
5、最长公共子串
# 求两个字符串的公共子串 # s1 = 'abcdefg' # s2 = 'defabcd' # def findit(str1,str2): # length = len(str1) # for step in range(length,0,-1): # 倒序 # for start in range(0,length-step+1): # 从开始到倒序最大值 # substr = str1[start:start+step] # 0-7,0-6、1-7...... # if str2.find(substr) > -1: # return substr # print(findit(s1,s2))
# 矩阵算法 s1 = 'abcdefg' s2 = 'defabcd' s3 = 'defabcdoabcdeftw' s4 = '1234a' s5 = '5678' def findit(str1,str2): matrix = [] xmax = 0 xindex = 0 for i,x in enumerate(str2): matrix.append([]) for j,y in enumerate(str1): if x != y: matrix[i].append(0) else: if x == 0 or y == 0: matrix[i].append(1) else: matrix[i].append(matrix[i-1][j-1]+1) if matrix[i][j] > xmax: xmax = matrix[i][j] xindex = j xindex += 1 return str1[xindex - xmax:xindex] print(findit(s1,s2))
6、打印树
import math def print_tree(array): index = 1 depth = math.ceil(math.log2(len(array))) # 结点补零之后 sep = ' ' for i in range(depth): offset = 2**i print(sep*(2**(depth-i-1)-1),end='') line = array[index:index + offset] for j, x in enumerate(line): print("{:>{}}".format(x,len(sep)),end='') interval = 0 if i ==0 else 2**(depth-i)-1 if j<len(line)-1: print(sep*interval,end='') index += offset print() print_tree([0,30,20,80,40,50,10,60,70,90])
7、递归函数斐波那契
# 斐波那契 import datetime start = datetime.datetime.now() def fib(n): return 1 if n < 2 else fib(n-1) + fib(n-2) for i in range(35): print(fib(i),end=" ") # pre = 0 # cur = 1 # print(pre,cur,end=" ") # def fib(n,pre=0,cur=1): # pre,cur=cur,pre+cur # print(cur,end=" ") # if n == 2: # return 1 # fib(n-1,pre,cur) # print(fib(5)) delat = (datetime.datetime.now() - start).total_seconds() print() print(delat)