1、高阶函数python
python中函数是一等对象(first class);函数也是对象,而且它能够像普通对象同样复制、做为参数、做为返回值。
编程
返回函数或者参数是函数的函数就是高阶函数,也被称为函数式编程
bash
In [23]: def counter(base): ...: def inc(x=1): ...: nonlocal base ...: base += x ...: return base ...: return inc # 返回一个函数 ...: In [24]: inc = counter(3) In [25]: inc Out[25]: <function __main__.counter.<locals>.inc> In [26]: inc() Out[26]: 4 In [27]: inc() Out[27]: 5
内置函数sorted()的实现:闭包
In [48]: def sort(it, cmp=lambda a, b: a<b): ...: ret = [] ...: for x in it: ...: for i, e in enumerate(ret): ...: if cmp(x, e): ...: ret.insert(i, x) ...: break ...: else: ...: ret.append(x) ...: return ret ...: In [49]: sort([1, 3, 5, 2, 4, ]) Out[49]: [1, 2, 3, 4, 5] In [50]: sort([1, 3, 5, 2, 4, ], lambda a, b: a>b) Out[50]: [5, 4, 3, 2, 1]
总结:
app
函数做为返回值经常使用于闭包的场景:须要封装一些变量ssh
函数做为参数经常使用于大多数逻辑固定,少部分逻辑不固定的场景ide
函数做为参数,返回值也为是函数:经常使用于做为参数的函数在执行先后须要一些额外的操做(增长功能)函数式编程
2、装饰器函数
一、装饰器
工具
函数的参数是一个函数,返回值也是一个函数,就能够做为装饰器
In [77]: def add(x, y): ...: return x + y ...: In [78]: add.__name__ Out[78]: 'add' In [80]: def logger(fn): ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} called'.format(fn.__name__)) ...: return ret ...: return wrap ...: In [81]: loged_add = logger(add) In [82]: loged_add(3, 5) call add add called Out[82]: 8
简单、优雅一点:
In [90]: def add(x, y): ...: return x + y ...: In [91]: def logger(fn): ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} called'.format(fn.__name__)) ...: return ret ...: return wrap ...: In [92]: add = logger(add) # add变量名被从新赋值定义,赋值是先执行右边的部分 In [93]: add(3, 4) call add add called Out[93]: 7
更简单、优雅:
In [102]: def logger(fn): ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} called'.format(fn.__name__)) ...: return ret ...: return wrap ...: In [103]: @logger # @这是装饰器的语法糖,至关于 add=logger(add)=wrp ...: def add(x, y): ...: return x + y ...: In [104]: add(1, 2) call add add called Out[104]: 3
这是logger就是装饰器了
3、装饰器的反作用
被装饰的函数函数名发生了改变
In [73]: add.__name__ # 被装饰的函数函数名改变了 Out[73]: 'wrap' In [74]: help(add) Help on function wrap in module __main__: wrap(*args, **kwargs)
python是自文档语言:
In [78]: def fn(): ...: print('hello') ...: In [79]: help(fn) Help on function fn in module __main__: fn() (END) In [82]: def fn(): ...: '''this is fn''' ...: print('hello') ...: In [83]: help(fn) Help on function fn in module __main__: fn() this is fn (END) In [84]: fn.__doc__ Out[84]: 'this is fn' In [85]: fn.__name__ Out[85]: 'fn' In [86]: dir(fn) # 查看全部的属性和方法 Out[86]: ['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
解决办法:
In [87]: def logger(fn): ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} clled'.format(fn.__name__)) ...: return ret ...: wrap.__name__ = fn.__name__ ...: wrap.__doc__ = fn.__doc__ ...: return wrap ...: In [88]: @logger ...: def add(x, y): ...: return x+y ...: In [89]: add.__name__ Out[89]: 'add' In [90]: add(1, 2) call add add clled Out[90]: 3
能够将解决办法写成一个函数:
def copy_proprities(src, dst): dst.__name__ = src.__name__ dst.__doc__ = src.__doc__ # 这个函数能够写成装饰器 In [91]: def copy_proprities(src): ...: def _copy(dst): ...: dst.__name__ = src.__name__ ...: dst.__doc__ = src.__doc__ ...: return _copy ...: # 在装饰器函数中调用它 In [92]: def logger(fn): ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} clled'.format(fn.__name__)) ...: return ret ...: copy_proprities(fn)(wrap) ...: return wrap ...: In [93]: @logger ...: def add(x, y): ...: return x+y ...: In [94]: add.__name__ Out[94]: 'add' In [95]: add(1, 2) call add add clled Out[95]: 3
将解决方案写成一个装饰器:
In [102]: def copy_proprities(src): ...: def _copy(dst): ...: dst.__name__ = src.__name__ ...: dst.__doc__ = src.__doc__ ...: return dst ...: return _copy ...: In [103]: def logger(fn): ...: @copy_proprities(fn) ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} clled'.format(fn.__name__)) ...: return ret ...: return wrap ...: In [104]: @logger # add=logger(fn)=wrap ...: def add(x, y): ...: return x+y ...: In [105]: add.__name__ Out[105]: 'add' In [106]: add(1,3) call add add clled Out[106]: 4
实际上标准中已经实现了这个功能:
In [119]: import functools In [120]: def logger(fn): ...: @functools.wraps(fn) ...: def wrap(*args, **kwargs): ...: print('call {}'.format(fn.__name__)) ...: ret = fn(*args, **kwargs) ...: print('{} clled'.format(fn.__name__)) ...: return ret ...: return wrap ...: In [121]: @logger ...: def add(x, y): ...: return x+y ...: In [122]: add.__name__ Out[122]: 'add'
4、类型提示
类型提示是python3新增的功能
python是动态类型语言,一个变量的类型,是在代码运行时决定的
一个变量的类型在应用的生命周期中是可变的
In [4]: a = 1 In [5]: type(a) Out[5]: int In [6]: a = 'xxj' In [7]: type(a) Out[7]: str
在函数中:
In [8]: def add(x, y): ...: return x+y ...: # 对于这个函数咱们可能会这样调用,由于咱们不知道它须要的参数类型 In [9]: add("a", "b") Out[9]: 'ab' In [10]: add(1, 2) Out[10]: 3 In [11]: add('a', 2) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-11-fc7c9413859a> in <module>() ----> 1 add('a', 2) <ipython-input-8-aa3fbbe3d526> in add(x, y) 1 def add(x, y): ----> 2 return x+y TypeError: must be str, not int In [12]: help(add) # 帮助文档中也没有说明须要什么类型的参数 Help on function add in module __main__: add(x, y) (END)
解决办法:
In [15]: def add(x, y): ...: '''x + y ...: @param x int ...: @param y int ...: @return int ...: ''' ...: return x + y ...: In [17]: help(add) Help on function add in module __main__: add(x, y) x + y @param x int @param y int @return int (END)
这里可能会有以下问题:
并非每一个人都会记得写文档
文档并不能保证和代码一块儿更新
文档是天然语言,不方便机器操做
因此在Python3中新增了类型提示这个特性:
In [18]: def add(x: int, y:int) -> int: ...: return x + y ...: In [19]: add(1, 2) Out[19]: 3 In [20]: help(add) Help on function add in module __main__: add(x:int, y:int) -> int (END) In [31]: add.__annotations__ Out[31]: {'return': int, 'x': int, 'y': int}
类型提示(类型注解),只是一个注释,不会做任何检查
In [22]: add('a', 'b') # 不检查,不转换;就只是一个注释 Out[22]: 'ab'
但在一些IDE工具中会有警告信息
因此类型注解能够提供给第三方工具使用(IDE, 静态分析),或者在运行时获取信息
在python3.5以前,类型注解只能用在函数参数和返回值