一、高价函数和柯里化
-
First Class Object函数在 Python 中是一等公民函数也是对象,可调用的对象函数可以作为普通变量、参数、返回值等
-
高阶函数数学概念 y=g(f(x))在数学和计算机科学中,高阶函数应该是至少满足下面一个条件的函数:接受一个或多个函数作为参数输出一个函数
-
sorted(iterable[,key][,reverse])返回一个新的列表,对一个可迭代对象的所有元素排序,排序规则为 key 定义的函数,reverse 表示是否排序翻转,sorted() 返回新列表,list.sort() 就地修改
-
filter(function,iterable) –> filter object过滤可迭代对象的元素,返回一个迭代器function 一个具有一个参数的函数,返回 bool>>> list(filter(lambda x:x%3==0,[1,9,55,150,-3,78,28,123])) –> [9, 150, -3, 78, 123]
-
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))) –> {0: 495, 1: 496, 2: 497, 3: 498, 4: 499}
-
柯里化:指的是将原来接受两个参数的函数编程新的接受一个参数的函数的过程,新的函数返回一个以原有第二个参数的函数,z = f(x,y) 转换成 z = f(x)(y) 的形式,通过嵌套函数就可以把函数转换成柯里函数
二、装饰器
-
最简单的用法def logger(fn):def wrapper(*args,**kwargs):print(‘BEGIN’)x = fn(*args,**kwargs)print(‘END’)return xreturn wrapper@loggerdef add(x,y):return x+yadd(100,2)
-
装饰器(无参)它是一个函数函数作为它的形参返回值也是一个函数可以使用 @functionname 方法,简化使用
-
装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)
-
文档字符串Python 是文档字符串 Documetation Strings在函数语句块的第一行,且习惯是多行的文本,所以多使用三引号惯例是首字母大写,第一行写概述,空一行,第三行写详细描述可以使用特殊属性 __doc__ 访问这个文档
-
带参装饰器它是一个函数函数作为它的形参返回值是一个不带参的装饰器函数使用 @functionname(参数列表) 方式调用可以看做在装饰器外层又加了一层函数
-
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 函数使用的时候只需要加上一句:import functools functools.update_wrapper(wrapper,fn)
-
@functools.wraps(wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)类似 copy_properties 功能wrapped 被包装函数元组 WRAPPER_ASSIGNMENTS 中是要被覆盖的属性:’__module__’(模块名)、’__name__’(名称)、’__qualname__’(限定名)、’__doc__’(文档)、’__annotations__’(参数注解)元组 WRAPPER_UPDATES 中是要被更新的属性,__dict__ 属性字典增加一个 __wrapped__ 属性,保留着 wrapped 函数使用的时候只需要加一句:import functools @functools.wraps(fn)
-
partial 方法偏函数,把函数部分的参数固定下来,相当于为部分的参数添加了一个固定的默认值,形成一个新的函数并返回从 partial 生成的新函数,是对原函数的封装def partial(func,*args,**keywords):def newfunc(*fargs,**fkeywords):newkeywords = keywords.copy()newkeywords.update(fkeywords) # 如果有关键字参数,就更新值return func(*(args + fargs),**newkeywords) # 如果全是位置参数,就在后面追加newfunc.func = func # 保留原函数newfunc.args = args # 保留原函数的位置参数newfunc.keywords = keywords # 保留原函数的关键字参数return newfunc
-
@functools.lru_cache(maxsize=128,typed=False)Least-recently-used 装饰器,lru 即最近最少使用,cache 缓存如果 maxsize 设置为 None,则禁用 LRU 功能,并且缓存可以无限制增长,当 maxsize 是 2 的幂时,LRU 功能执行的最好如果 typed 设置为 True,则不同类型的函数参数将单独缓存,如 f(3) 和 f(3.0) 将被视为具有不同结果的不同调用使用方法:import functols @functools.lru_cache()通过一个字典缓存被装饰函数的调用和返回值lru_cache 装饰器应用使用前提:同样的函数参数一定得到同样的结果;函数执行时间很长,且要多次执行缺点:不支持缓存过期,key 无法过期、失效;不支持清除操作;不支持分布式,是一个单机的缓存适用场景:单机上需要空间换时间的地方,可以用缓存来将计算变成快速的查询
三、参数注解
-
函数定义的弊端Python 是动态语言,变量随时可以被赋值,且能赋值为不同的类型Python 不是静态编译型语言,变量类型是运行器决定的
-
解决动态语言定义的弊端:增加文档 Documentation String这只是一个惯例,不是强制标准,不能要求程序员一定为函数提供说明文档函数定义更新了,文档未必同步更新
-
解决动态语言定义的弊端:函数注解def add(x:int,y:int) -> int:”’:param x:int:param y:int:return:int”’return x + yadd(4,5) –> 9add(‘mag’,’edu’) –> ‘magedu’
-
函数注解Python 3.5 引入对函数的返回值进行类型注解对函数的返回值进行类型注解只对函数参数做第一个辅助的说明,并不对函数参数进行类型检查提供给第三方工具,做代码分析,发现隐藏的 bug函数注解的信息,保存在 __annotations__ 属性中add.__annotations__ –> {‘return’: str, ‘x’: int, ‘y’: str}
-
inspet 模块:提供获取对象信息的函数,可以检查函数和类、类型检查inspect.isfunction(add),是否是函数inspect.ismethod(add),是否是类的方法inspect.isgenerator(add),是否是生成器对象inspect.isgeneratorfunction(add),是否是生成器函数inspect.isclass(add),是否是类inspect.ismodule(add),是否是模块inspect.isbuiltin(add),是否是内建对象signature:获取签名(函数签名包含了一个函数的信息,包括函数名、它的参数新类型、它所在的类型和名称空间及其他信息)
-
Parameter 对象保存在元组中,是只读的name,参数的名字annotation,参数的注解,可能没有定义default,参数的缺省值,可能没有定义empty,特殊的类,用来标记 default 属性或者注释 annotation 属性的空值kind,实参如何绑定到形参,就是形参的类型POSITIONAL_ONLY,值必须是位置参数提供POSITIONLY_OR_KEYWORD,值可以作为关键字或者位置参数提供VAR_POSITIONLY,可变位置参数,对应 *argsKEYWORD_ONLY,keyword-only参数,对应 * 或者 *args 之后的出现的非可变关键字参数VAR_KEYWORD,可变关键字参数,对应 **kwargs
四、堆排序
-
堆(Heap)堆是一个完全二叉树每个非叶子结点都要大于或者等于其左右孩子结点的值称为 大顶堆每个非叶子结点都要小于或者等于其左右孩子结点的值称为 小顶堆根结点一定是大顶堆中的最大值,一定是小顶堆中的最小值
-
构建大顶堆的核心算法度数为 2 的结点 A,如果它的左右孩子结点的最大值比它大,将这个最大值和该结点交换度数为 1 的结点 A,如果它的左孩子的值大于它,则交换如果结点 A 被交换到新的位置,还需要和其孩子结点重复上面的过程
-
构建大顶堆的起点结点选择从完全二叉树的最后一个结点的双亲结点开始,即最后一层的最右边叶子结点的父结点开始结点数为 n,则起始结点的编号为 n//2构建大顶堆的下一个结点的选择从起始结点开始向左找其同层结点,到头后再从上一层的最右边结点开始继续向左逐个查找,直至根结点排序将大顶堆根结点这个最大值和最后一个叶子结点交换,那么最后一个叶子结点就是最大值,将这个叶子结点盘排除在待排序结点之外,然后从新的根结点开始,重新调整为大顶堆后,重复上一步
-
总结是利用堆性质的一种选择排序,在堆顶选出最大值或者最小值由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏,平均时间复杂度为 O(nlogn)只是使用了一个交换用的空间,空间复杂度为 O(1)不稳定的排序算法
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/97001