高阶函数、柯里化及装饰器的使用


高阶函数python

数学概念的引入:程序员

例 y = g(f(x))数据结构

数据来源自另外一个函数,y带到g函数,从而又赋值给y闭包

 

高阶函数的特性app

在数学和计算机科学中,高阶函数至少知足如下任意一个条件ide

 

在数学中,高阶知足如下两个条件之一:函数

1.接受一个或多个函数做为参数,对于g来说的话总体算是一个自变量优化

例:将g作为一个自变量spa

y =g(f1(x),f2(x))操作系统

 

2.输出一个函数

输出一个值,这里的值是函数对象的帧,并不是是函数返回值

 

参数中使用了函数对象,若是输出的是一个函数,则知足的是一个高阶函数

简单讲,参数中出现函数或者return中出现函数则都被称为高阶函数

 

例:

defcounter(base):

    definc(step=1):

        nonlocalbase

        base+= 1

        returnbase

    returninc()

 

foo =counter(10)

print(foo)

 

foo1 =counter(11)

print(foo1)

 

11

12

 

查看foo和foo1的id地址进行比较

 

foo =counter(10)

print(id(foo))

foo1 =counter(11)

print(id(foo1))

 

494806032

494806064

 

由于inc是counter的某一对象,在赋值的过程当中发生了id更变,因此foo 生成的对象自己不同

能够做为一个本地的变量去了解

 

在堆中作对象的建立 ,堆中是乱序的,后期由虚拟机进行垃圾回收;

栈: 由操做系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操做方式相似于数据结构中的栈。

堆: 通常由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式却是相似于链表。

 

在堆中的对象建立,都是为inc建立的,inc赋值给foo

因此foo1 和 foo的地址不同,当第一次调用counter;

需counter进行压栈并将参数标记压栈,建立栈帧,并建立临时对象inc

inc进行return 交给外部变量,由于最后要retrun,return之后的代码要被从栈中清空


 

引用是在堆上,并不是在栈,inc所对应的对象须要等值进行赋予,在堆上直接引用地址,因此堆不会被清理

 

自定义sort方法

首先找到一个大值,遍历x的时候会取一个值并进行对列表遍历并匹配

若是列表是空的则不会进入循环,直接append到新的列表中

第一次的时候直接进入到ret中,ret如今是1,那么再获取31 再与ret中比较,ret重只有一个1

31比1大,那么在当前位置中插入元素(这里是与ret的当前位置进行索引插入)

lst =[1,31,4,7,3,21,8]

defsort(items):

    ret= []

    forx in items:        #遍历lst

        fori,y in enumerate(ret):        #对下标进行标注

            ifx > y:                    #拿出第一个元素依次对比列表中的元素,若是大于当前值则在最前面追加索引

                ret.insert(i,x)   

                break

        else:

            ret.append(x)

    returnret

print(sort(lst))

 

 

 

改进:对其添加默认参数及判断优化

lst =[1,31,4,7,3,21,8]

defsort(items,reverse=False):

    ret= []

    forx in items:

        fori,y in enumerate(ret):

            flag= x > y if  not reverse else x < y    #flag为标记,若是反向说明这个是true

            

            ifflag:        # 判断其布尔值

               ret.insert(i,x)

                break

        else:

            ret.append(x)

    returnret

print(sort(lst))

使用flag 无非是判断reverse参数的真假值,用于正反向

print(sort(lst,reverse=False))

print(sort(lst,reverse=True))

 

flag= x > y if  not reverse else x < y

至关于:

            ifreverse:

                flag= x > y

            else:

                flag= x < y  

 

 

 

再次改进:

使用嵌套函数实现判断reverse

lst= [1,31,4,7,3,21,8]

defsort(items,reverse=False):

    defcomp(a,b):                        # 用ab去接受xy 的值

        flag= a > b if reverse else a < b

        returnflag                       # 返回flag的布尔值

    ret= []

    forx in items:

        fori,y in enumerate(ret):

            ifcomp(x,y):                  # 判断flag的布尔值是x > y仍是y<x

                ret.insert(i,x)

                break

        else:

            ret.append(x)

    returnret

print(sort(lst,reverse=True))

 

再次改进,将通用函数放置函数外部

lst= [1,31,4,7,3,21,8]

defsort(items,reverse=False):

    defcomp(a,b,reverse):        #用ab去接受xy

         flag= a > b if reverse else a < b

    ret= []

    forx in items:

        fori,y in enumerate(ret):

            ifcomp(x,yreverse):

                ret.insert(i,x,reverse)

                break

        else:

            ret.append(x)

    returnret

print(sort(lst,reverse=True))

 

 

再次改进:

经过参数传参调用外部函数(外部函数为一个通用函数)进行

在外部函数控制内部函数的排序逻辑,升序或者降序,这样使得咱们的函数更加灵活

 

lst =[1,31,4,7,3,21,8]

defcomp(a,b):

    returna < b

 

defsort(items,key=comp,reverse=False):

    ret= [ ]

    forx in items:

        fori ,y in enumerate(ret):

            flag= key(x,y) if reverse else key(y,x)

            #if comp(x,y):

            ifflag:

                ret.insert(i,x)

                break

        else:

            ret.append(x)

    returnret

print(sort(lst,reverse=True))

 

 

使用lambda替换comp函数

 

defsort(lst,key=lambda a,b : a < b,reverse=False):        # 经过key的传参的布尔值来控制升序或降序

    ret= [ ]

    forx in lst:

        fork,v in enumerate(ret):

            flag= key(x,k) if reverse elsekey(k,v)        # 判断函数的布尔值来替换排序的位置,真为x>k 假为x < k

            ifflag:

                ret.insert(k,x)

                break

        else:

            ret.append(x)

    returnret

print(sort(lst,reverse=True))

print(sort(lst,reverse=False))

 

 

 


 

 

总结:

所谓高阶函数的参数由外界的传入;

首先基本函数成型,将其抽取参数,判断分支结构进行拆解造成外部函数

 

 

内建函数

sorted       排序

filter       过滤数据,只保留想获取的部分

map          映射

 

sorted  经过key作排序进行规则定义,只能作同类型的数据处理

In [7]:lst = [1,31,4,7,3,21,8]

 

In [8]:sorted(lst,reverse=True)

Out[8]:[31, 21, 8, 7, 4, 3, 1]

 

In [9]:sorted(lst,reverse=False)

Out[9]:[1, 3, 4, 7, 8, 21, 31]

 

In[25]: a = lambda x: 6 -x

In[26]: a(7)

Out[26]:-1

 

In[32]: sorted(lst,key=lambda x:31-x)

Out[32]:[31, 21, 8, 7, 4, 3, 1]

就地修改

In[37]: lst

Out[37]:[1, 31, 4, 7, 3, 21, 8]

In[38]: lst.sort()

In[39]: lst

Out[39]:[1, 3, 4, 7, 8, 21, 31]

 

In[46]: lst.sort(key=lambda x:1)

In[47]: lst

Out[47]:[31, 21, 8, 7, 4, 3, 1]

比较临时值,追加元素自己,key并非修改原来元素,之是为了临时比较得出临时值

 

filter

 

只能过滤可迭代的对象元素,并返回一个迭代器

返回迭代器说明是同一份数据,function一个具备一个参数的函数,返回一个布尔值

迭代器说明作一些大量数据作一些处理,因此迭代器比较合适

 

In[60]: list( filter(lambda x:x%3 == 0 ,[_ for _ in range(10)]))

Out[60]:[0, 3, 6, 9]

 

a =filter(lambda x: x%3 == 0 ,(_ for _ in range(10)))

#print(list(a))

[0, 3,6, 9]

 

至关于:

lst =[1,2,3,4,5,6]

deffn(x,ret=[]):

    forx in x:

        ifx % 3 == 0:

            ret.append(x)

    returnret

print(fn(lst))

 

至关于咱们自行编写的sort函数,一个x参数表示对每一个参数进行判断并过滤,x拿到元素以后查看是否能够被3整除,由于生成器是惰性求值,因此并不会当即返回

 

map

map可收集n个可迭代对象,并生成迭代器

将各类类型进行迭代,能够是元组、字典、list 均可以

In[65]: lambda x:x%3==0,[2,3,4,5,6,7,8,9,11,12,13]

Out[65]:(<function __main__.<lambda>>, [2, 3, 4, 5, 6, 7, 8, 9, 11, 12,13])

 

In[66]: map(lambda x:x%3==0,[2,3,4,5,6,7,8,9,11,12,13])

Out[66]:<map at 0x7f22901cb278>

 

In [68]:dict(map(lambda x:(x,x%3==0),[2,3,4,5,6,7,8,9,11,12,13]))

Out[68]:

{2:False,

3:True,

4:False,

5:False,

6:True,

7:False,

8:False,

9:True,

11:False,

12:True,

13:False}

 

In[71]: dict(map(lambda x:(x%3,x),[2,3,4,5,6,7,8,9,11,12,13]))

Out[71]:{0: 12, 1: 13, 2: 11}

 

In[76]: dict(map(lambda x:(x+1,x),range(10)))

Out[76]:{1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, 8: 7, 9: 8, 10: 9}

 

字典生成过程必须是一个二元组

总结:

map主要是生成一个新的值,从一个元素映射到另外一个元素

map 直接转换,将原来的某个操做添加封装以另外一种形式返还

 

filter 只保留当前须要的元素,其余丢弃(python中不会当即修改,而是惰性求值,,由于返回的都是迭代器)

sorted不会就地修改

 

高阶函数简单来说,在参数中出现了函数,二者知足其一则被称为高阶函数

全部的函数封装除了嵌套函数(由于须要用到闭包)都须要听从这样的原则

 

#将核心逻辑改成可变的,由于函数是一等公民

 

 

柯里化

数学概念,将原来接受两个参数的函数整合为一个新的能够接受一个参数函数的过程

新的函数返回一个原有第二个参数做为参数的函数

 

z = f(x,y)转为 z = f(x)(y)

 

defadd(x):

    def_add(y):

        returnx + y

    return_add

print(add(4)(6))

 

需求来了:

一个加法函数,想加强它的功能,可以被调用过以及调用的参数信息

defadd(x,y):

    returnx + y

 

#改成:

defadd(x,y):

    print('call,x+y')

    returnx + y

 

使用__name__特殊对象来获取对象名称

funcname.__name__

 

defadd(x,y,file):

    print('{},{}+ {}'.format(add.__name__,x,y,file=file))

    #print(add.__name__)

    returnx + y

 

add(4,5,file='file')

add,4 +5

 

file是一个形参,后面file以关键字参数传参

 

首先打印语句耦合性过高,与add函数混在一块儿,

打印函数是否属于加法?咱们须要将非业务的需求也加入进来,因此须要加入到业务函数是不合适的,这样的写法叫作侵入式

 

可是又想对函数进行功能性加强

 

对业务作出分离

 

defadd(x,y):

    returnx + y

 

deflogger(fn):

    print('before')

    ret= fn(4,5)

    print('after')

    returnret

logger(add)

 

 

但这里的参数依旧是写死的,改进:

defadd1(x,y):

    returnx + y

 

defadd2(x,y,z):

    returnx + y + z

 

deflogger(fn,*args,**kwargs):

    ret= fn(*args,**kwargs)

    returnret

 

print(logger(add2,3,4,5))

 

 

再次改进:

定义一个函数,进行运算,经过闭包方式调用add进行传参

并返回结果

 

defadd(x,y,z):

    returnx + y + z

 

deflogger(fn,*args,**kwargs):

    def_logger(*args,**kwargs):

        ret= fn(*args,*kwargs)

        returnret

    return_logger

 

print(logger(add)(1,2,3))

 


 

 

引用装饰器

等于add1 = logger(add1)

 

对比:

defadd(x,y,z):

    returnx + y + z

 

deflogger(fn,*args,**kwargs):

    def_logger(*args,**kwargs):

       return fn(*args,*kwargs)

    return_logger

 

print(logger(add)(1,2,3))

 

修改成:

deflogger(fn):

    def_logger(*args):            #造成一个闭包

        print('123 43 4')         #为了看到效果并非直接调用add函数,在这里直接打印一些内容做为标记

        returnfn(*args)

    return_logger

@logger

defadd1(*args):

    i= 0

    forx in args:

        i+= x

    returni

 

print(add1(1,2,3,4))

 

12 3 434

10

 

装饰器 等于 add = logger(add)

装饰器只能接一个参数,参数就是add标识符

 

装饰器语法

无参装饰器

·它是一个函数

·函数做为它的参数

·返回值也必须是一个函数

 

deflogger(fn):

    defwapper(*args):    

        print('begin')

        x= fn(*args)

        print('end')

        returnx

    returnwapper        

 

@logger

defadd(x,y):

    returnx + y

print(add(1,2))

 

 

装饰器确定是一个高阶函数,不断传入函数,并返回一个内层函数

 

 

总结对比

 

defadd1(*args):

    i= 0

    forx in args:

        i+= x

    returni

#########################################

deftest(fn):

    def_test(*args):

        print(111111)

        returnfn(*args)

    return_test

@test

defabc(*args):

    i= 0

    forx in args:

        i+= x

    returni

print(abc(1,2,3))

 

 

 

 

文档字符串

__doc__string

使用要求:在函数第一个表达式,必须是个字符串

defadd1(x,y):

    ret= x,y

    returnret

add1(1,100)

print(add1.__name__)

add1

 

 

 

defadd1(x,y):

    '''hellopython

enenenen'''

    ret= x,y

    returnret

add1(1,100)

print(add1.__doc__)

 

hellopython

enenenen

 

 

 

函数的帮助自己就是调用__doc__()

 

使用装饰器改logger,添加说明

 

deflogger(fn):

    def_logger(*args):

        'thiis logger'

        print('logger')

        returnfn(*args)

    return_logger

 

@logger

defadd(x,y):

    returnx + y

print(add.__name__,add.__doc__,sep='\n')

 

_logger

thi islogger

看到这里打印的是logger函数内的信息

name和doc是对象的属性,因此,咱们能够经过一个新的函数对其进行控制

 

 

 

定义一个新的函数用于标记被调函数的属性

defcopy_pro(src,dst):

    dst.__name__= src.__name__

    src.__doc__= dst.__doc__

 

defcopy_pro(src,dst):

    dst.__name__= src.__name__

    dst.__doc__= src.__doc__

 

deflogger(fn):

    def_logger(*args):

        'thiis logger'

        print('logger')

        returnfn(*args)

    copy_pro(fn,_logger)

    return_logger

 

@logger

defadd(x,y):

    'hahaha'

    returnx + y

 

print(add.__name__,add.__doc__,sep='\n')

add

hahaha

 

 


将 _logger 的__doc__ 和 __name__ 指向了 add.__name__ , add__doc__

 

logger定义过了,源已经赋值给了目的,src被带入了fn也就是add,doc是add 字符串

这样就把属性改成同样的

 

__qualname__  是函数的限定名称

print(add.__qualname__,sep='\n')

logger.<locals>._logger

 

 

简化:将拷贝函数作为装饰器进行封装

被包装函数的文档等一切属性则会消失

 

改造:带参装饰器

提供一个函数,被封装函数属性copy() 包装函数属性

defcopy_pro(src):

    def_copy(dst):

        dst.__name__= src.__name__

        dst.__doc__= src.__doc__

        dst.__qualname__= src.__qualname__

        returndst

    return_copy

 

deflogger(fn):

    @copy_pro(fn)

    defwrapper(*args,**kwargs):

        x= fn(*args,**kwargs)

        returnx

    returnwrapper

 

@logger

defadd(x,y):

    returnx + y

print(add(1,2))

print(add.__qualname__)

 

 

 

python自己提供了拷贝函数

经过自定义函数将被包装函数属性覆盖掉包装函数

凡被装饰装饰的函数都须要复制这些属性,比较通用

能够将复制属性的函数构建成装饰器函数 -- 带参装饰器

 

带参装饰器,带参装饰器无非加了一层函数

例:将大于50秒的语句筛出

参数值只能传一个,因此须要与其替换次序

importdatetime

importtime

 

deflogger(t):

    def_logger(fn):

 

        defwrap(*args,**kwargs):

            start= datetime.datetime.now()

            ret= fn(*args,**kwargs)

            duration= int((datetime.datetime.now() - start).total_seconds())

            ifduration > t:

                print("{}took {}".format(fn.__name__,duration.total_seconds()))

 

            returnret

        returnwrap

    return_logger

 

@logger(30)

defadd(x,y):

    time.sleep(5)

    returnx + y

 

print(add(33,y=7))

 

以上就能够将经过外部提供的函数来灵活的控制输出

 

 

functools模块

 

import functools

 

deflogger(fn):

    @functools.wraps(fn)

    def_logger(*args):

        'thiis logger'

        print('logge!!!!!!!!!!!r')

        returnfn(*args)

    #copy_pro(fn,_logger)

    return_logger

 

@logger

defadd(x,y):

    'hahaha'

    returnx + y

 

print(add(2,3))

print(add.__qualname__,add.__doc__,sep='\n')

 

logge!!!!!!!!!!!r

5

add

hahaha

相关文章
相关标签/搜索