zoukankan      html  css  js  c++  java
  • 高阶函数和装饰器

    高阶函数的定义:
    函数也可以是对象,或者可以调用的对象
    函数可以作为普通变量,参数,数值等等
         数学概念: y =g(f(x))
         高阶函数应该是一个至少满足下面一个条件的函数
              接受一个或多个函数作为参数
              输出一个函数
     
    自己写一个排序的函数:
    def sort(iterable):
    lst = []
    for i in iterable:
         for j,m in enumerate(lst):
    if i > m:
                    lst.insert(j,i)
                    break
         else:
              lst.append(i)
    return lst
     
    lst1=[9,5,4,7,6,5,1]
    print(sort(lst1))
    自己实现sort排序之flag版:
     
    def sort(iterable,reverse=Flase):         #(reverse默认为假,非False即为真)
         lst=[]
         for i in iterable:
              for j,m in enumerate lst:
                   flag=i>m if reverse else i<m                    #(客户可在函数后增加 参数进行判断升降序)
                   if flag:
                        lst.insert(j,i)
                        break
              else:
                   lst.append(i)
         return lst
     
    lst1=[8,7,6,2,1,4,9]
    print(sort(lst1,reverse的参数))  
    自己实现sort排序之函数版(进阶):
    def sort(iterable,key=lambda a,b:a<b):     #定义升降序的默认值
      lst = []
      for i in iterable:
                 for j, m in enumerate(lst):
                     flag=key(i,m)                 #返回布尔值(True,False)
                     if flag:
                         lst.insert(j, i)
                         break
                 else:
                     lst.append(i)
      return lst
     
    lst1 = [8, 7, 6, 2, 1, 4, 9]
    print(sort(lst1,lambda a,b:a>b))
    filter(function,iterable)
         过滤可迭代对象的元素。返回一个迭代器
         function 一个具有一个参数的函数,返回bool值
         举例:
    list(filter(lambda x : x%3,range(50)))
         就会过滤出50以内所有的能被3整除的数字
     
    map(function,*iterbale)-->object
         对多个可迭代对象的元素按照指定的函数进行映射,返回一个迭代器
     
    柯里化函数
    柯里化的定义:
    将原来接收两个参数的函数变成新的接收一个参数的函数的过程,新的函数返回一个以原有第二个参数为参数的函数
          Z=f(x,y)转换成Z=f(x)(y)的方式    
    通过嵌套函数就可以把函数转换成柯里化函数
    def nums(x):
         def nums1(y):
              nonlocal x
              x+=y
              return x
         return nums1
    foo = nums(5)
    foo(6)
     
    工作中,业务代码只执行特定的业务,而其他的则需要在装饰器的帮助下实现增强语句
    例如一个函数为:
    def sum(x,y):
          value=x+y
          return value
    这个代码只执行一个计算的程序,我称之其为业务代码,如果我想在其上下添加‘语句块’但是又不想入侵这个业务代码,就需要利用到装饰器了
    def coat(key):
         def pants(x,y):
              print('wow,you look so great')
              fn=key(x,y)
              print('i love it')
              return fn
         return pants
    @coat          #sum=coat(sum)
    def sum(x,y):
         value=x+y
         return value
    这就是一个简单的装饰器,在不入侵业务代码的同时,也可以对其进行增强,当让远不止打印几句话这种简单用法,可以添加 时间,计数等等
    不适用装饰器的弊端:
    打印语句的耦合性太高
    逻辑运算属于业务功能,而输出信息的功能,属于非业务功能代码,不能出现在 务语法中
     
    做到了业务功能分离,但是fn的函数调用传参是个问题
    def add(x,y):
         return x+y
    def logger(fn):
         print('begin')
         x= fn(4,5)
         print('end')
         return x
     
    print(logger(add)) 
     
    使用装饰器解决:
    def logger(fn):
         def _logger(*args)
              print('begin')
              x= fn(*args)
              print('end')
              return x
    @logger               #add=logger(add)
    def add(x,y):
         return x+y
     
    add(4,5)
    输出结果为 
    begin
    end
    9
    这段代码在不入侵业务代码的同时,也加入了想要的内容,这种方法就叫做装饰器
    无参装饰器
         它是一个函数
         函数作为它的形参
         返回值也是一个函数
         使用@函数引用 方式,简化代码
     
    一些简单的无参装饰器代码:
    import datetime
    import time
     
    def looger(fn):
             def warp(*args,**kwargs):
                 # 增强功能
                 print('args={},kwargs={}'.format(args,kwargs))      #声明传进来的是什么东西
                 start = datetime.datetime.now()
                 ret = fn(*args,**kwargs)
                 end = datetime.datetime.now() - start
                 print('founc{} took {}s.'.format(warp.__name__,end.total_seconds()))     #打印函数执行时长
       return ret
             return warp
     
    def add(x,y):
           print('===call add=========')
           time.sleep(2)
           return x + y
     
    print(add(5,6))
     
    代码2(差别小):
    import datetime
    import time
    def logger(new):
             def warp(*args,**kwargs):
                 print('args={} kwargs={}.'.format(args,kwargs))
                 start=datetime.datetime.now()
                 ret = new(*args,**kwargs)
                 times=datetime.datetime.now() - start
                 print('func {} need {}s.'.format(warp.__name__,times))
                 return ret
      return warp
     
    @logger
    def combo(x,y=10):
             time.sleep(2)
             return (x+10)*3-1
     
    print(combo(40,y=97))
    图形化理解装饰器的作用:::::::
     
    一副画不能随便涂改,所以可以在裱画的同时,对画外面的部分进行一些改动,达到既不改动画的同时,又能达到改动的效果,而画(业务代码)只有一副,但是各种各样的画框(装饰器函数)却可以有多种样式
     
     
    查询一个函数的文档:
    为什么要写文档帮助,可以帮你查找函数的附加信息,可以方便你识别其功能
    函数的帮助文档只能在第一行显示
    帮助文档的首字母尽量大写
    第一行写概述 空一行,第三行再写详细描述
    使用三引号,可以换行
    示例:
    def add(x,y):
         '''this is function
     
         thx'''
         ret=x+y
         return ret
    print(add.__doc__)
    利用代参装饰器,进行业务代码外的函数文档复制,使其内外一致
     
    def copy_(src):
         def wapper(dct):
              src.__name__ =dct.__name__
              src.__doc__ =dct.__name__
              return dct
         return wapper
     
    import datetime
    import time
    def logger(fn):
             @copy_(fn)   #原公式为 @copy_.waper=>logger.warp=copy_.wapper(logger.warp)
             def warp(*args,**kwargs):
                 '''
                 this is function
     
                 '''
                 print('args={} kwargs={}.'.format(args,kwargs))
                 start=datetime.datetime.now()
                 ret = fn(*args,**kwargs)
       times=datetime.datetime.now() - start
                 print('func {} need {}s.'.format(warp.__name__,times))
                 return ret
      return warp
     
    @logger
    def combo(x,y=10):
       time.sleep(2)
       return (x+10)*3-1
     
    print(combo(40,y=97))
     
    def add(x,y):
         '''this is function
         x = int
         y = int
     
         thx'''
         ret=x + y
         return ret
    print(add.__doc__)
    疯狂写代码之 代参函数装饰器示例:
    def coop(old):
         def cood(new):
              new.__name__=old.__name__
              new.__doc__=old.__doc__
          return new
    return cood
     
    import datetime
    import time
     
    def word(t):
         def dayss(fn):
              def wordadd(*args):
                   '''this is wodradd wordadd '''
                     start=datetime.datetime.now()
                     print('im a super student')
                     tec=fn(*args)
                     end=(datetime.datetime.now() - start).total_seconds()
                     if end > t:
                         print('you program is so slow , you can write it again ')
                     else:
                         print('you need {}s to make this complete'.format(end))
                     return tec
               return wordadd
         return dayss
     
    @word(t=50)
    def add(x,y):
         '''this is add help words'''
         time.sleep(2)
         return x + y
     
    print('''Function:{};
    Helpword={};
    The result of his executionis {}'''.format({add.__name__},{add.__doc__},{add(4,5)}))
    代参装饰器:
    它是一个函数
    函数为他的形参
    返回值是一个不带参的装饰器函数
    使用@funcition(参数列表)方式调用
    可以看作在装饰器外又加了一层函数
     
    文档字符串:
    python 是文档字符串DOCumentation Strings
    在函数语句块的第一行,一般是多行的文本,使用三引号
    习惯:首字母大写,第一行概述,空一行,第三行写详细描述
    可以使用特殊属性 __doc__来访问这个函数的文本文档
    查看方式:    help(函数对象)
     
    装饰器的副作用:
    使用装饰器后的函数所显示出的文本文档不在是被包装函数的文本文档信息,而是显示包装函数的文档信息,所以在封装函数的同时也要考虑函数对象的文档信息是否是自己想要看到的
    解决办法1:
    可以再写一个拷贝函数;
         new.__name__=old.__name__
         new.__doc__=old.__doc__
    将此函数作为装饰器对业务代码再次进行包装,这样所显示的文本文档就是最初的文本文档了
    凡是需要属性复制的都可以调用这个装饰器进行包装,所以这个函数很通用
     
    founctools模块(需要导入)
    functools.update__wrapper(wrapper,wrapped,assigned=WRAPPER__ASSIGNMENTS,updated=WRAPPER_UPDATES)
    其功能和拷贝类似
    wrapper包装函数      wrapped被包装函数
    元组WRAPPER_ASSIGNMENTS中是要被覆盖的属性
    '__module__,__name__,__doc__,__qualname__,__annotations__)' 
    模块,名字,文档,限定名,参数注解
    元组WRAPPER_UPDATES中是要被更新的属性,__dict__ 属性字典
    增加一个_wrapped__属性保留着wrapped函数
     
    functools的用法:
    import datetime,time,functools:
    def logger(durtion,func=lambda name,duration:print('{} took {}s'.format(name,duration))):
         def __logger(fn):
              @functools(fn)
              def wrapped(*args):
          start = datetime.datetime.now()
          ret =  fn(*args)
          delta = (datetime.datetime.now()-start).total.seconds()
          if delta > duration:
                 func(__name__,duration)
                   return ret
             return  wrapped
         return __logger
     
    @logger(5)               # add = logger(5(add)
    def add(x,y):
         time.sleep(2)
         return x+y
     
    print(add(5,6),add.__name__,add.__dict__,add.wrapped__,sep='
    ')

    温故而知新,知识还是要巩固的呀

  • 相关阅读:
    Python_turtle绘图实例(持续更新)
    C++程序设计实验考试准备资料(2019级秋学期)
    利用next_permutation()实现全排列 完成 阮小二买彩票
    用埃氏算法来素数求和
    C++指针注意事项
    double与float的输入输出格式
    图片文件隐写术
    文件操作与隐写
    MFC 消息机制
    MFC应用中处理消息 创建窗口和会话框的顺序
  • 原文地址:https://www.cnblogs.com/spidermansam/p/7716221.html
Copyright © 2011-2022 走看看