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