一、高阶函数

    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)