高阶函数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,y,reverse):
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