python高阶函数与装饰器

##**高阶函数**
– 函数是python中的一等公民
– 函数也是对象,可调用对象
– 函数可以作为普通变量、参数、返回值等等
– 数学概念y = g(f(x))
– 高阶函数满足以下至少一个条件:1.接收一个或多个函数作为参数 2.输出一个函数

##**举例(计数器)**
def counter(base):
def inc(step=1):
nonlocal base #base在这里自由变量,闭包。
base += step
return base
return inc
>上述代码 f1 = counter(5) 和 f2 = counter(5),其f1与f2不相等。他们在堆里面不是同一个对象创建。

##**自定义sort函数(版本1)**
def sort(iterable):
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([1,2,5,4,2,3,5,6]))

##**自定义sort函数(版本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

##**自定义sort函数(版本3)**
def sort(iterable, fn=lambda a,b : a>b): #函数写进参数里
ret = [ ]
for x in iterable:
for i, y in enumerate(ret):
if fn(x, y): # 返回一个bool值
ret.insert(i,x)
break
else:
ret.append(x)
return ret
print(sort([1,2,5,4,2,3,5,6]))

##**内建高阶函数**
1.排序 :sorted(iterable,[,key][,reverse])
> 返回一个新的列表,对一个可迭代对象的所有元素排序,排序规则为key定义的函数,reverse表示是否排序翻转。

2.过滤 :filter(function, iterable) –> filter object
> (1) 过滤可迭代对象的元素,返回一个迭代器
(2) function一个具有一个参数的函数,返回bool
(3) 过滤能被3整除的数 list(filter(lambda x: x%3==0, [1,9,55,150,-3,78,28,123]))

3.映射 :map(func, *iterables) –> map object
> 对多个可迭代对象的元素按照指定的函数进行映射,返回一个迭代器
list(map(lambda x:2*x+1, range(5)))
[1, 3, 5, 7, 9]
dict(map(lambda x: (x%5,x) , range(500))) #相同key的值被覆盖,所以只有五个
{0: 495, 1: 496, 2: 497, 3: 498, 4: 499}

##**柯里化currying**
– 定义:指的是将原来接收两个参数的函数变成新的接收一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数
##举例
def add(x, y):
return x + y
转换为如下:
def add(x): #通过嵌套函数可以完成柯里化
def _add(y):
return x+y
return _add
add(5)(6)

##**装饰器(无参)**
- 它是一个函数
- 函数作为它的形参
- 返回值也是一个函数
- 可以使用@functionname方式,简化调用
- 装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)

##举例
 import datetime
 import time
 def logger(fn):
 def wrap(*args, **kwargs):
 # before 
 print("args={}, kwargs={}".format(args,kwargs))
 start = datetime.datetime.now()
 ret = fn(*args, **kwargs)
 # after 
 duration = datetime.datetime.now() - start
 print("function {} took {}s.".format(fn.__name__, duration.total_seconds()))
 return ret
 return wrap
 @logger #add = logger(add)
 def add(x, y):
 print("===call add===========")
 time.sleep(2)
 return x + y
 print(add(4, y=7))
 
##**文档字符串**
- python是文档字符串Documentation Strings
- 在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号
- 惯例是首字母大写,第一行概述,空一行,第三行写详细描述
- 可以使用特殊属性__doc__访问这个文档
##
 def add(x,y):
 """This is a function of addition"""
 a = x+y
 return x + y
 print("name={}\ndoc={}".format(add.__name__, add.__doc__))
 print(help(add))

##**装饰器例子**
 def logger(fn):
 def wrapper(*args,**kwargs):
 'I am wrapper'
 print('begin')
 x = fn(*args,**kwargs)
 print('end')
 return x
 return wrapper
 @logger #add = logger(add)
 def add(x,y):
 '''This is a function for add'''
 return x + y
 print("name={}, doc={}".format(add.__name__, add.__doc__))
>上述例子有副作用,原函数对象的属性都被替换了,而使用装饰器,我们的需求是查看原函数的属性。
 
##解决方法 
 def copy_properties(src, dst): 
 dst.__name__ = src.__name__
 dst.__doc__ = src.__doc__
 装饰其中调用copy_properties(fn, wrapper)
 
##**完整解决方案**
 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 = wrapper(fn)(wrapper)
 def wrapper(*args,**kwargs):
 'I am wrapper'
 print('begin')
 x = fn(*args,**kwargs)
 print('end')
 return x
 return wrapper
 @logger #add = logger(add)
 def add(x,y):
 '''This is a function for add'''
 return x + y
 print("name={}, doc={}".format(add.__name__, add.__doc__))
 
##**带参装饰器**
- 它是一个函数
- 函数作为它的形参
- 返回值是一个不带参的装饰器函数
- 使用@functionname(参数列表)方式调用
- 可以看做在装饰器外层又加了一层函数

##获取函数的执行时长,对时长超过阈值的函数记录一下
 def logger(duration):
 def _logger(fn):
 @copy_properties(fn) # wrapper = wrapper(fn)(wrapper)
 def wrapper(*args,**kwargs):
 start = datetime.datetime.now()
 ret = fn(*args,**kwargs)
 delta = (datetime.datetime.now() - start).total_seconds()
 print('so slow') if delta > duration else print('so fast')
 return ret
 return wrapper
 return _logger
 @logger(5) # add = logger(5)(add)
 def add(x,y):
 time.sleep(3)
 return x + y
 print(add(5, 6))
 将记录的功能提取出来,这样就可以通过外部提供的函数来灵活的控制输出
 def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
 def _logger(fn):
 @copy_properties(fn) # wrapper = wrapper(fn)(wrapper)
 def wrapper(*args,**kwargs):
 start = datetime.datetime.now()
 ret = fn(*args,**kwargs)
 delta = (datetime.datetime.now() - start).total_seconds()
 if delta > duration:
 func(fn.__name__, duration)
 return ret
 return wrapper
 return _logger
 
##**functools模块**
- functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)
- 类似copy_properties功能
- wrapper包装函数,wrapped被包装函数
- 元组WRAPPER_ASSIGNMENTS中是要被覆盖的属性'__module__', '__name__', '__qualname__', '__doc__', '__annotations__
- 元组WRAPPER_UPDATES中要是被更新的属性,__dict__属性字典
- 增加一个__wrapped__属性,保留着wrapped属性

##**functools模块应用**(functools.update_wrapper)
 import datetime, time, functools
 def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
 def _logger(fn):
 def wrapper(*args,**kwargs):
 start = datetime.datetime.now()
 ret = fn(*args,**kwargs)
 delta = (datetime.datetime.now() - start).total_seconds()
 if delta > duration:
 func(fn.__name__, duration)
 return ret
 return functools.update_wrapper(wrapper, fn)
 return _logger
 @logger(5) # add = logger(5)(add)
 def add(x,y):
 time.sleep(1)
 return x + y
 print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep='\n')

##**functools模块应用**(functools.wraps)
 import datetime, time, functools
 def logger(duration, func=lambda name, duration: print('{} took {}s'.format(name, duration))):
 def _logger(fn):
 @functools.wraps(fn)
 def wrapper(*args,**kwargs):
 start = datetime.datetime.now()
 ret = fn(*args,**kwargs)
 delta = (datetime.datetime.now() - start).total_seconds()
 if delta > duration:
 func(fn.__name__, duration)
 return ret
 return wrapper
 return _logger
 @logger(5) # add = logger(5)(add)
 def add(x,y):
 time.sleep(1)
 return x + y
 print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep='\n')
 

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/88028

(0)
miraclermiracler
上一篇 2017-10-23 10:39
下一篇 2017-10-23 14:47

相关推荐

  • History的作用及调用历史命令的快捷方式

    History的作用及调用历史命令的快捷方式 M21-陆东贵 CentOS 7.2 命令历史:shell进程会在其回话中保存此前用户提交执行过的命令; history命令:命令历史; 命令语法:history [-c] [-d 偏移量] [n] 或           …

    Linux干货 2016-10-19
  • 配置yum服务器——以centOS 6.9系统为例

    准备工作 关闭防火墙  关闭防火墙service iptables stop  设置防火墙开机不启动chkconfig iptables off  查看一下防火墙状态 iptables -vnL 如下图,可以看到已经关闭 关闭SElinux 使用命令 vim /etc/selinux/config 将SELINUX=enable…

    Linux干货 2017-08-05
  • 学习的第二周

    硬链接不能跨分区,硬链接不支持对目录的创建, 硬链接的本质是一个文件N个节点  ls |xargs rm 解决参数太长 无法正常删除的问题。   软连接 依赖于原始文件 删除就没了软连接可以跨分区,可以根据目录创建软连接,而且还可以针对文件夹 软连接依赖于原始文件。原始文件删了软连接就打不开了  相对路径一般相对当前工作目录,但…

    Linux干货 2017-05-30
  • 基础命令

    1,对于Linux的实验环境我们要用到虚拟机,往往每次上线都要登录,这时候如果把用户设为自动登录就会方便许多,接下来就介绍下设置虚拟机的自动登录 , /etc/gdm/custom.conf 这个就是设置自动登录的一个配置文件,我们先来使用nano打开这个文件,如下 # GDM configuration storage 这是GDM的一个配置存储 [daem…

    2017-11-19
  • linux用户权限管理

       在linux文件系统中使用ls -l命令可以查看文件的属性,但是我们明白其中属性各自代表的意思吗?下面我们就来看一看,这其中的奥义。。。 文件属性 使用ls命令查看文件,可以发现列表分为几个部分,各自所代表的意义如图所示: 文件属性操作     chown 设置文件的所有者  &nb…

    Linux干货 2016-08-04
  • 干货 | 20 行 Python 代码创建可视化地图

    当我开始建造Vincent时, 我的一个目的就是使得地图的建造尽可能合理化. 有一些很棒的python地图库-参见Basemap 和 Kartograph能让地图更有意思. 我强烈推荐这两个工具, 因为他们都很好用而且很强大. 我想有更简单一些的工具,能依靠Vega的力量并且允许简单的语法点到geoJSON文件,详细描述一个投影和大小/比列,最后输出地图. …

    2017-09-08