高阶函数&&装饰器
高阶函数
- first class object
- 函数在python中是一等公民
- 函数也是对象,可调用的对象
- 函数可以作为普通比变量、参数、返回值
- 高阶函数
- 数学概念:y = g(f(x))
- 在数学和计算机科学中,高阶函数应当是至少满足下面一个条件的函数
- 接受一个或多个函数作为参数
- 输出一个函数,return 函数
- 举例:
#nonlocal base#不加此行会有什么影响?调用时会提示base无定义
UnboundLocalError Traceback (most recent call last)
<ipython-input-336-624891b0d01a> in <module>()
<ipython-input-334-2a9fcd38455a> in inc(step)
UnboundLocalError: local variable ‘base’ referenced before assignment
注意:大的对象都是在堆里面创建
f1 = counter(5)和f2 = counter(5),相等吗?
单纯counter是一样的,但是由于返回值时一个新的对象inc,而inc相当于常量在堆中创建f1 、 f2在堆中为不同的空间
自定义sort函数
#代码一:
for i,y in enumerate(ret):
if x > y:#找到大的就地插入。如果x<y则升序
print(sort([4,3,4,5,2,1,9,8]))
def sort(iterable,reverse=False):#定义函数
for i,y in enumerate(ret):
flag = x > y if not reverse else x < y#默认是降序,去掉not则为升序,此方法是通过传参实现控制
if flag:#找到大的就地插入。如果x<y则升序
print(sort([4,3,4,5,2,1,9,8]))
def sort(iterable,fn=lambda a,b:a<b):#使用匿名函数传参
for i,y in enumerate(ret):
#fn = lambda x,y:x>y#此方法也阔以
if fn(x,y):#函数调用获取返回值,控制参数即可
print(sort([4,3,4,5,2,1,9,8]))
- sorted(iterable[,key][,reverse])排序
- 返回一个新的列表,对一个可迭代带向的所有元素排序,排序规则为key定义的函数,reverse表示是否排序翻转
- sorted(lst,key=lambda x:6-x)#返回新列表,此处并没有修改列表的值而是通过值来决定是大于还是小于,所以此处是倒序排列,大值变小小值变大。
- lst.sort(key=lambda x:6-x)#就地修改
sorted(lst,key=lambda x:6-x)
lst.sort(key=lambda x:6-x)
[9, 8, 5, 4, 4, 3, 2, 1]#结果可证实上面理论部分
filter(function,iterable)
* 过滤可迭代对象元素,返回一个迭代器。惰性求值
* function一个具有一个参数的函数,返回bool
filter(lambda x:x%3 == 0,[1,9,55,150,-3,78,28,123])
<filter at 0x7fe1840e9a20>
list(filter(lambda x:x%3 == 0,[1,9,55,150,-3,78,28,123]))
[9, 150, -3, 78, 123]#此处用列表转换可以直接获取结果
map(function,*iterables)—>map object
- 对多个可迭代对象的元素按照指定的函数进行映射,返回一个迭代器
list(map(lambda x:2*x+1,range(5)))
dict(map(lambda x:(x%5,x),range(500)))
{0: 495, 1: 496, 2: 497, 3: 498, 4: 499}#显示这个结果的原因是key值不允许重复
柯里化Currying
- 定义:将原来接受两个参数的函数变成新的接受一个参数的函数过程,新的函数返回一个以原有第二个参数为参数的函数
- z = f(x,y)转换成z = f(x)(y) 形式虽不同但是结果是一样的
#举例:将加法函数柯里化
return add2#重点:让add的返回值去调用add2这样就可以关联xy
装饰器
- 应用场景:
- 一个加法函数,想增强它的功能,能够输出被调用过以及调用的参数信息
- def add(x,y):
- 现增加输出功能
- def add(x,y):
- print(“call add,x + y”)
- return x+y
- 上面的函数是完成了需求,但是有以下缺点:
- 打印语句的耦合太高
- 加法函数属于业务功能,而输出信息的功能属于非业务代码,不该放在业务函数加法中,这属于代码侵入
- 下列代码做到了业务功能分离,但是fn函数调用参数是个问题
def logger(fn):#此处也可写成(fn,*args,**kwargs)来完成传参需求
@logger#装饰器将下方紧邻的函数作为参数传递给装饰器函数,add为wrapped,fn为wrapper。等价于 add = logger(add),所以add是biu的对象
- 装饰器(无参)
- 他是一个函数
- 函数作为他的形参
- 返回值也是一个函数
- 可以使用@functionname方式,简化调用
- 装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)
- 装饰器造成的问题:
- 原函数对象的属性都被替换了,而使用装饰器,我们需要查看被装饰函数的属性如何解决?
#解决方法一:定义一个新函数,作用:将被修饰函数的属性重新赋予修饰函数
def copy_properties(src,dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
def wrapper(*args,**kwargs):
copy_properties(fn,wrapper)
@logger#add = logger(add)–>return wrapper
”’This is a function for add”’
print(‘name={},doc={}’.format(add.__name__,add.__doc__))
#通过copy_properties函数将被包装函数的属性覆盖到包装函数
#凡是被装饰器的函数都需要复制这些属性,这个函数很通用
#可以将复制属性的函数构建成装饰器函数,带参装饰器如下方法:
def copy_properties(src):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
@copy_properties(fn)# wrapper = copy_properties(fn)(wrapper)
def wrapper(*args,**kwargs):
@logger#add = logger(add)–>return wrapper
”’This is a function for add”’
print(‘name={},doc={}’.format(add.__name__,add.__doc__))
- 需求:获取函数的执行时长,对时长超过阈值的函数记录一下
import datetime
def copy_properties(src):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
@copy_properties(fn)# wrapper = copy_properties(fn)(wrapper)
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
delta = (datetime.datetime.now() – start).total_seconds()
print(‘so slow’) if delta > duration else print(‘so fast’)
@logger(5) #add = logger(5)(add)–>return wrapper
”’This is a function for add”’
- 带参装饰器:
- 他是一个函数
- 函数作为他的形参
- 返回值是一个不带参的装饰器函数
- 返回@functionname(参数列表)方式调用
- 可以看做在装饰器外层又加了一层函数
- 将记录的功能提取出来,这样就可以通过外部提供的函数来灵活控制
import datetime
def copy_properties(src):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
def logger(duration,func=lambda name,duration: print(‘{} took {}s’.format(name,duration))):
@copy_properties(fn)# wrapper = copy_properties(fn)(wrapper)
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
delta = (datetime.datetime.now() – start).total_seconds()
func(fn.__name__,duration)
@logger(5) #add = logger(5)(add)–>return wrapper
”’This is a function for add”’
funtools模块
- functools.update_wrapper(wrapper,wrapped,assigned=WRAPPER_ASSIGNMENMENTS,updated=WRAPPER_UPDATES)
- 类似copy_properties功能
- wrapper包装函数,wrapped被包装函数
- 元组WRAPPER_ASSIGNMENTS中是要被覆盖的属性__module__,__name__,__qualname__,__doc__,__annotations__模块名、名称、限定名、文档、参数注解
- 元组WRAPPER_UPDATES中是要被更新的属性,__dict__属性字典
- 增加一个__wrapped__属性,保留着wrapped函数
import datetime
def logger(duration,func=lambda name,duration: print(‘{} took {}s’.format(name,duration))):
@copy_properties(fn)# wrapper = copy_properties(fn)(wrapper)
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
delta = (datetime.datetime.now() – start).total_seconds()
func(fn.__name__,duration)
return functools.update_wrapper(wrapper,fn)
@logger(5) #add = logger(5)(add)–>return wrapper
”’This is a function for add”’
print(add(5,6),add.__name__,add.__wrapped__,add.__dict__,add.__doc__,sep=’\n’)
##使用装饰器调用functools
def logger(duration,func=lambda name,duration: print(‘{} took {}s’.format(name,duration))):
def wrapper(*args,**kwargs):
start = datetime.datetime.now()
delta = (datetime.datetime.now() – start).total_seconds()
func(fn.__name__,duration)
@logger(5) #add = logger(5)(add)–>return wrapper
”’This is a function for add”’
print(add(5,6),add.__name__,add.__wrapped__,add.__dict__,add.__doc__,sep=’\n’)
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/88039