了解
首先,函数式编程是一种编程范式即编写程序的方法。在编程的过程中,可以在函数传参时传入一函数、赋值给变量、也可以在函数返回时返回一个函数。
在使用时需要注意:
- 尽量值产生需要的值不改变全局变量的值
- 不依赖于外部变量或"状态",只依赖输入的参数,任何时候只要参数相同,引用函数所得到的返回值相同的
- 使用传入的参数来保存状态
优点:
- 减少代码的重复,开发快
- 易于理解
- 每个函数独立、单元测试更加简单
- 不用考虑死锁,因为不修改变量,存结果也只是存到参数中【易于实现并发
看起来类似于C++中的函数指针,只是函数式编程更加灵活、函数可能会有变化
函数指针是一种特殊的指针,它指向函数的入口
高阶函数
map:
传入一函数及一个可迭代对象,将函数应用到可迭代对象中的每个数据上:
def f(x):
return x*x
m=map(f,[1,2,3,4,5,6,7,8,9])
list(m)
print(m)
print(list(m))
在使用后注意输出的形式
这里使用for循环也可以完成这一功能,但明显map更加明了。
reduce:
将函数作用在序列上,将结果从序列第一个往后做一个累计。eg:reduce(f,[a,b,c,d])---->f(f(f(a,b),c),d)
如将序列转化为一个整数:
from functools import reduce
def f(x, y):
return x * 10 + y
reduce(f,[5,6,2,3,4,5,7])
上面两个函数结合实现将字符串转化为整型:
from functools import reduce
def f(x,y):
return x*10+y
def char2num(s):
digits=['0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9]
return digits[s]
reduce(f,char2num('5623457'))
filter:
接收一函数与序列,与map不同的是filter根据函数返回值是True或False来决定是否丢弃该元素,所以filter主要用于过滤序列。
eg:删除掉序列中的空字符
def not_empty(s):
return s and s.strip()
list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))
sorted:
可以直接对list中数字进行比较——作为普通函数;
sorted([7,21,-18,16])
#-18,7,16,21
接收一个key函数实现自定义的函数——作为高阶函数;
sorted([7,21,-18,16,9,-13],key=abs)
#7,9,-13,16,-18,21
字符串实现忽略大小写的反向排序:
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower,reverse=True)
['about', 'bob', 'Credit', 'Zoo']
返回函数
在使用函数返回时,在直接调用函数名时func
,返回的是函数而非函数值。只有调用函数:func()
时,才返回函数计算结果
同一函数,即使调用相同的参数,返回的仍然是新的函数,且相互之间不会影响
闭包:函数返回一个函数后,该函数的局部变量仍然被新的函数引用。
使用时注意:返回函数不要用循环变量或后面可能改变的变量,如果一定要用可以加一个函数使用参数对变量进行绑定
匿名函数
lambda表示匿名函数,eg:lambda x : x * x
这里冒号前面的x为参数,lambda只能有一个表达式,该函数结果为返回值
用匿名函数有一个好处,不必但心命名冲突,且匿名函数也可作为返回值
装饰器
函数对象有一__name__属性,查看函数的名字(给变量复制的函数,变量取该属性仍然为该函数名)
装饰器【decorator】:在代码运行期间,动态增加函数功能的方式。
函数定义的上一行有@functionName的修饰,当解释器读到@的这样的修饰符之后,会先解析@后的内容,直接就把@下一行的函数或者类作为@后边的函数的参数,然后将返回值赋值给下一行修饰的函数对象
eg:@log
def fun():
相当于log(fun)
这里的log若为装饰器,将返回一个新的函数,此时虽然fun()函数依然存在,但fun却指向了新的函数。
偏函数
通过设定参数的默认值,降低使用难度。
functools.partial可以创建一个偏函数的,不需要自己定义,可以直接用函数=functools.partial(int, base=。。。)