Python函数式编程
Python函数式编程
TOC
- 函数参数中的魔法
- 位置参数
- 默认参数
- 动态参数
- 位置参数收集
- 关键字参数收集
- 收集参数行为的逆向过程(这个逆向过程用于实参上)
- 参数传递
- 函数嵌套
- 命名空间
- 作用域
- 闭包
- 函数式编程
- 装饰器
- 显示方式
- @方式
- 带参数装饰器
- functools.wraps(func)
- 匿名函数
- 高阶函数
- 三剑客
- filter()
- map()
- reduce()
- sorted()
- 三剑客
- 递归函数
函数参数中的魔法
coming...
嵌套函数
顾名思义就是一个函数定义中嵌套了一个函数的定义。说道嵌套函数,就必须先介绍命名空间和作用域
命名空间NameSpace
python分三类命名空间。内置,全局,本地。包括一个区域,封闭区域。
- Builtins 内置空间,在main模块加载前创建
- Globals 全局空间,模块为单位。包空间其实是__init__.py模块
- Enclosing 封闭区域
- Locals 本地空间,函数,类,对象等
作用域Scope
python对象的作用域是遵照LEGB规则。
闭包
一般普通的函数嵌套并没什么特别的用处。但是嵌套函数有个突出的应用,也是非常强大的应用。就是,通过外层函数创建一个函数,即返回内层函数,外层函数每一调用返回的内层函数,这些返回的内层函数之间是独立的函数对象。他们都“继承”了外层函数调用时的作用域。这个“继承”行为我们称为闭包。
闭包显著的特点就是:返回的内层函数中,使用了外层函数的局部变量或者参数参与内层函数的运算。这些变量和参数的值还是外部函数调用返回前时的值。 要注意的是:返回内层函数时,使用外层函数时的变量或者参数,如果在返回后发生了变化。那么内层函数后面调用会使用变化后的值,而不是返回内层函数那个时间点的值了。所以很多博客都在强调,闭包返回的内层函数不要引用还会在外层函数发生变化的变量。 要解决这个问题,可以采取中间变量(中间变量就是固定的了)或者再嵌套一个中间函数,让这个中间函数来获取变化的变量,在传递给最内层的函数,并返回最内层的函数。
记住:内层函数返回时是不会执行的。
__自己猜想__ 有点类似于面向对象,一个对象方法返回另一个对象,新对象的实例化是受到返回它的对象影响,展现除了多态的特性。闭包有点多态,继承,封装(函数本来就是一种封装形式)的意思,将规律相似的作为一层。多层次之间可以看作多层次的嵌套函数来设计,能产生“继承变量”的哪一层就作为上层,有几层规律就嵌套几层函数,从外到内,每一层都是和上一层有一个或多个“继承变量”关系。算一种设计范式了吧。 如:乘法运算,将第一个乘数作为一层,第二乘数提供后算出乘积来作为第二层。那么就可以使用闭包将拆分有关系的两层进行程序设计。 再如:装饰器函数的inner()函数,就是要继承装饰函数说传递的参数。返回的inner函数调用就会间接调用被装饰的函数。inner函数实现了扩展需求的功能。 找点装饰器或者其它闭包例子来佐证猜想
函数式编程
摘自廖雪峰python教程
函数式编程是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数是没有变量的,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
python 对函数式编程提供部分支持。由于Python允许使用变量,因此Python不是纯函数式编程语言。
装饰器Decorator
装饰器是函数式编程的集大成应用。涉及高阶函数,闭包,参数传递等。
如果只是要扩展功能,只需要再创建一个函数,并嵌套需要扩展的函数,就是在创建的函数中实现扩展功能后,再执行扩展前的函数就可以了。但是这样做有一个缺点就是,原函数名被改变了,这样会被调用原函数的其它部门打死的,你这样方便了自己却麻烦了其他人。
那就要想办法呀,那重命名这个扩展的函数为原函数名呢?肯定不行,这样函数调用就编程了递归函数了。
那就这样设计:用一个函数返回一个函数,返回的函数重命名为原来的函数名。调用这个重命名返回函数,就是执行扩展后再调用原函数。这就是通过闭包,实现装饰器。
- 装饰外层函数:返回内层函数
- 装饰内层函数:实现原功能上的“封闭-开发”原则的扩展功能。内层函数对扩展功能实现后,再调用原函数,并return原函数调用返回值。
显示方式
# 我们已一个廖老师装饰器思考题为例,说明两种方式表示装饰器的应用 # 题目:请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间 import time def runtime(func): def wrapper(*args, **kwargs): t1 = time.time() res = func(*args, **kwargs) t2 = time.time() print((t2-t1)) return res return wrapper def get_sum(*args): sums = 0 for i in args: sums += i return sums get_sum = runtime(get_sum) # 这就是显示方式 print(get_sum(*list(range(10000))))
@方式
# 装饰器函数一样 import time def runtime(func): def wrapper(*args, **kwargs): t1 = time.time() res = func(*args, **kwargs) t2 = time.time() print((t2-t1)) return res return wrapper @runtime # 这里就是@方式,等价于上面的 显示方式 def get_sum(*args): sums = 0 for i in args: sums += i return sums print(get_sum(*list(range(10000))))
结果:
0.0010001659393310547 #运行时间
49995000 #函数返回值
使用装饰器扩展的功能变得更具兼容性,高内聚。(带参数装饰器)
什么意思呢?翻译成‘人话’就是:一般装饰器只扩展一类相似功能的一种,现在要给这一功能提供并传递参数,是装饰器展现出不同的行为。
装饰器带上参数,只需要再装饰器包裹一个函数,这个函数接收参数,返回一个外层装饰器函数,内层函数接受到包裹的哪层函数的参数,在扩展代码中进行应用,这样使得扩展代码具有更多变数,理所当然,也会拿到外层还是传递的原函数。内层函数拿到这两个东西,就可以大施拳脚,做出各种功能来了。
直接代码说话:
# 廖老师的打印调用一个函数的日志。 def log(text): def outer(func): def inner(*args, **kwargs): print("%s begin call " % text) return func(*args, **kwargs) return inner retrun outer @log('求和') def get_sum(*args): sums = 0 for i in args: sums += i return sums print(get_sum(*list(range(10000))))
运行结果:
求和 begin call # 扩展的功能:打印执行日志
49995000 # 函数返回结果
让装饰器更安全
因为装饰器的内层函数被重新绑定给了原函数名,内层函数的__name__还是内层函数名,而不是原函数名。有些依赖函数签名的代码可能会报错。python的functools提供了
将内层函数的__name__值变为重新绑定到的变量的名字。
用法:
import functools def decorator(func) @functools.wraps(func) # 用在这里,就是wrapper之前,无论带参数还是不带参数的装饰器 def wrapper(*args, **kwargs): pass return func(*args, **kwargs) return wrapper
装饰器还可以不止一个参数,多个参数,多层包裹,产生多个维度。
匿名函数
匿名函数就是不需要显示的通过def定义函数。匿名函数通常用于高阶函数。匿名函数直接用于高阶函数的参数或者return中,如果在return中,就形成了闭包。
关键字lambda 代表匿名函数
匿名函数表示方法:
lambda x, y : x + y
冒号前x, y是参数列表,冒号后面表达式的值作为函数的return值,且冒号后面只能是一个表达式,不能包含其它语句。如赋值语句,复合语句。可以使用三元表达式。
匿名函数可以缩短代码行数。
匿名函数例子:
L = list(map(lambda *args: lambda *innerargs: print(innerargs+args),[1,2,3,4,5,6,7])) for f in L: f(10)
结果:
(10, 1)
(10, 2)
(10, 3)
(10, 4)
(10, 5)
(10, 6)
(10, 7)
高阶函数
什么是高阶函数?
coming...
递归函数
coming....
上一篇: vue监听键盘事件的快捷方法【推荐】
下一篇: linux编写.sh脚本并赋权限问题