如有兴趣了解更多请关注我的个人博客https://07xiaohei.com/
(四)函数式编程
Python是面向对象的程序设计语言,也是面向过程的程序语言,同时也支持函数式编程。
Pyhon标准库functools 提供了若干关于函数的函数,提供了Haskell和Standard ML中的函数式程序设计工具。
Python中的函数与其他数据类型处于平等地位,因此函数可以赋值给变量,可以作为参数传入其他函数,存储在其他数据结构中,或者作为函数的返回值。
1. 作为对象的函数:
函数在Python中是作为对象存在的,故函数对象可以赋值给变量,然后调用该变量。
def printself():
print("123321")
copyfun = printself
copyfun()
数据结构内的函数:函数作为对象,也可以存储数据结构内部。
def fun1():
print("fun1")
def fun2():
print("fun2")
def fun3():
print("fun3")
map_fun = {1:fun1,2:fun2,3:fun3}
map_fun[2]()
#运行结果:
# fun2
函数作为参数和返回值:函数可以作为其他函数的参数和返回值,接受函数作为输入或返回函数的函数叫做高阶函数。
def fun_use(fun,list_use):
return fun(list_use)
print(fun_use(max,[1,2,3,4,5,6,3.4,7.2]))
# 运行结果:
# 7.2
def add(a,b):
return a+b
def sub(a,b):
return a-b
def fun_high(x):
if x==1:
return add
elif x==2:
return sub
else:
return None
fun_use = fun_high(1)
print(fun_use(2,1))
fun_use = fun_high(2)
print(fun_use(2,1))
#运行结果:
# 3
# 1
函数名实际上也是变量,可以让函数名指向其他对象,但是这样会导致原有的函数无法使用。
def add(a,b):
return a+b
add =10
print(add)
#运行结果:
# 10
嵌套函数、Lambda表达式也是函数式编程的一部分,详见之前的博客,下面介绍更进一步的内容。
2. Map、Filter 和 Reduce:
(1) map函数:
map 函数的功能是对可迭代对象中的每个元素都调用指定的函数,并返回一个map对象的iterator迭代器(可以转化为list对象)。
语法格式:map(function, iterable)
function参数表示传入的函数,可以是内置函数、自定义函数或者 lambda 匿名函数,iterable表示可迭代对象,可以是列表、元组等,允许一到多个。
一般用于对某个集合对象的全部值执行某个特定操作。
map() 函数由 C 语言实现,执行效率高。
例子如下:
list_use = [1,2,3,4,5,6,7,8,9]
list_new = list(map(lambda x:x*2, list_use))
print(list_new)
# 运行结果:
# [2, 4, 6, 8, 10, 12, 14, 16, 18]
(2) fiter函数:
filter函数的功能是对传入的可迭代对象中的每个元素,都进行函数判断,并返回True或者False,最后将返回 True 的元素组成一个新的可遍历的集合对象,返回其迭代器。
语法格式:filter(function, iterable)
function参数表示传入的函数,可以是内置函数、自定义函数或者 lambda 匿名函数,iterable表示可迭代对象,可以是列表、元组等,允许一到多个。
一般用于筛除可迭代对象的不想要的项。
list_use = [1,2,3,4,5,6,7,8,9]
list_new = list(filter(lambda x:x%2==0, list_use))
print(list_new)
# 运行结果:
# [2, 4, 6, 8]
(3)redeuce函数:
reduce() 函数通常用来对一个集合做一些累积操作。
语法格式:reduce(function, iterable)
function规定必须传入一个包含 2 个参数的函数;iterable 表示可迭代对象,可以是列表、元组等,允许一到多个。
reduce() 函数在Python 3.x 中已经从内置函数中被移除,在functools模块使用 ,需要导入functools模块。
reduce 函数一般用于总结或者概述数据集。
import functools
list_use = [3,4,5,6,7]
list_new = functools.reduce(lambda x,y:x+y, list_use)
print(list_new)
# 运行结果:
# 25
3. 函数装饰器:
(1)闭包:
是指在函数中嵌套其他函数时引用外部函数变量,即在一个内部函数中,对外部作用域的变量进行引用,内部函数即为闭包。
一般情况下,内部函数是外部函数的返回值。
闭包无法修改外部函数的局部变量。
举例:
def add_two(a):
def add_new(b):
return a+b
return add_new
print(add_two(2)(3))
# 运行结果:
# 5
(2)装饰器:
是闭包的一个应用,能够使得代码更简短。
装饰器是用于拓展原函数功能的一种函数,不需要修改原函数的内容和调用。
装饰器常用于授权、日志等行为。
语法格式:
def 装饰器函数名(唯一形参):
函数体
@装饰器函数名
def 被装饰的函数名(形参列表):
函数体
使用时直接调用被装饰的函数名即可。
装饰器函数的形参需要一个函数作为参数传入,同时需要在内部代码块执行该函数,以保证被装饰函数的正确执行。
传参时和带参数时需要装饰器函数嵌套函数,后面进行介绍。
Python内置了3种函数装饰器,分别是@staticmethod、@classmethod 和@property,我们也可以自己定义函数装饰器。
装饰器完成的内容:
- 将被装饰的函数作为参数传给装饰器函数(后面->前面)。
- 将被装饰的函数的返回值替换成装饰器函数的返回值(前面->后面)。
实际上,就是把装饰器函数的功能按一定逻辑顺序加入到被装饰的函数当中,使得原函数不需要修改。
因此,不用@函数也可以完成装饰器的功能,只是相对而言阅读比较困难。
例子如下:
def use_decorator_fun(used_for_decorator_fun):
print("添加新功能的位置,在被装饰的函数执行之前执行")
used_for_decorator_fun()
print("添加新功能的位置,在被装饰的函数执行之后执行")
return True
@use_decorator_fun
def used_for_decorator_fun():
print("执行正常功能中")
for i in range(1,11,2):
print(i,end=',')
print("\n执行完毕")
result = used_for_decorator_fun
if result:
print("执行成功")
# 运行结果:
# 添加新功能的位置,在被装饰的函数执行之前执行
# 执行正常功能中
# 1,3,5,7,9,
# 执行完毕
# 添加新功能的位置,在被装饰的函数执行之后执行
# 执行成功
如果不用@,可以是以下形式来表示:
def use_decorator_fun(used_for_decorator_fun):
print("添加新功能的位置,在被装饰的函数执行之前执行")
used_for_decorator_fun()
print("添加新功能的位置,在被装饰的函数执行之后执行")
return True
def used_for_decorator_fun():
print("执行正常功能中")
for i in range(1,11,2):
print(i,end=',')
print("\n执行完毕")
used_for_decorator_fun =use_decorator_fun(used_for_decorator_fun)
result = used_for_decorator_fun
if result:
print("执行成功")
# 运行结果:
# 添加新功能的位置,在被装饰的函数执行之前执行
# 执行正常功能中
# 1,3,5,7,9,
# 执行完毕
# 添加新功能的位置,在被装饰的函数执行之后执行
# 执行成功
可以看到,@use_decorator_fun只是换成了used_for_decorator_fun =use_decorator_fun(used_for_decorator_fun),不过此句的位置换到了两个函数定义之后。
这就是装饰器的实质。
(3)装饰器传参:
被装饰的函数带有参数时,需要对装饰器函数进行处理,以便前者为后者传递参数。
此时,需要为装饰器函数增加一个嵌套函数,嵌套的内部函数带有形参列表,如果其接收参数数量确定可以直接指定好形参列表数量,但多数时候参数数量是不固定的,此时使用前文已讲述的过的两个参数*args和**kwargs来完成接收任意数量参数的要求。
例子如下:
def fun_use_add(fun_use):
def fun_use_add_fact(a):
print("添加新功能的位置,在被装饰的函数执行之前执行")
fun_use(a)
print("添加新功能的位置,在被装饰的函数执行之后执行")
return True
return fun_use_add_fact
@fun_use_add
def fun_use(a):
print("执行正常功能中")
for i in range(1,a,2):
print(i,end=',')
print("\n执行完毕")
result = fun_use(11)
if result:
print("执行成功")
# 运行结果:
# 添加新功能的位置,在被装饰的函数执行之前执行
# 执行正常功能中
# 1,3,5,7,9,
# 执行完毕
# 添加新功能的位置,在被装饰的函数执行之后执行
# 执行成功
此时完成了一个参数的传递,如果参数不固定,可以改为:
def fun_use_add(fun_use):
def fun_use_add_fact(*args,**kwargs):
print("添加新功能的位置,在被装饰的函数执行之前执行")
fun_use(*args,**kwargs)
print("添加新功能的位置,在被装饰的函数执行之后执行")
return True
return fun_use_add_fact
@fun_use_add
def fun_use(a):
print("执行正常功能中")
for i in range(1,a,2):
print(i,end=',')
print("\n执行完毕")
result = fun_use(11)
if result:
print("执行成功")
# 运行结果:
# 添加新功能的位置,在被装饰的函数执行之前执行
# 执行正常功能中
# 1,3,5,7,9,
# 执行完毕
# 添加新功能的位置,在被装饰的函数执行之后执行
# 执行成功
(4)带参数的装饰器:
装饰器除了接收原函数任意类型和数量的参数,还可以接收自己定义的参数。
此时,需要在装饰器函数外部额外嵌套一层函数,该层负责接收自己定义的参数,内部代码块的对应return也要添加。
同时,在@处需要在函数名后增加要传入的实参,注意,此处必须传入对应参数。
例子如下:
def fun_use_parameter(a,b):
def fun_use_add(fun_use):
def fun_use_add_fact(*args,**kwargs):
print("添加新功能的位置,在被装饰的函数执行之前执行")
for i in range(1,a+1):
print("第"+str(i)+"次执行函数功能,函数功能序号为"+str(b))
fun_use(*args,**kwargs)
print("添加新功能的位置,在被装饰的函数执行之后执行")
return True
return fun_use_add_fact
return fun_use_add
@fun_use_parameter(2,5)
def fun_use(a):
print("执行正常功能中")
for i in range(1,a,2):
print(i,end=',')
print("\n执行完毕")
result = fun_use(11)
if result:
print("执行成功")
# 运行结果:
# 添加新功能的位置,在被装饰的函数执行之前执行
# 第1次执行函数功能,函数功能序号为5
# 执行正常功能中
# 1,3,5,7,9,
# 执行完毕
# 第2次执行函数功能,函数功能序号为5
# 执行正常功能中
# 1,3,5,7,9,
# 执行完毕
# 添加新功能的位置,在被装饰的函数执行之后执行
# 执行成功