Python学习(廖雪峰)笔记③——Python函数式编程
函数式编程 Functional Programming
特点:允许把函数本身作为参数传入另一个函数,还允许返回一个函数
Python:对函数式编程提供部分支持,由于Python允许使用变量,所以,Python不是纯函数式编程语言
高阶函数 Higher-order function
函数调用结果可以赋值给变量
变量可以指向函数,可以通过该变量来调用函数
函数名也是变量
传入函数
一个函数可以接收另一个函数作为参数,这样的函数就称为高阶函数
def add(x,y,f):
# f 为函数名
return f(x) + f(y)
map/reduce
map(function,Iterator)
map 将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
将运算规则抽象化
def f(x):
return x*x
L = [1,2,3,4,5,6,7,8,9,10]
r = map(f,L)
list(r)#结果r是一个Iterator,通过list()函数将整个序列都计算出来并返回一个list
reduce(function,Iterator)
function(parameter1 parameter2)
该函数需要接收两个参数
reduce
把结果和序列的下一个元素做累积计算(可以理解为不断嵌套?)
>>> from functools import reduce
>>> def fn(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(fn, map(char2num, '13579'))
#map函数通过将char2num函数应用到字符串'13579'上,将‘13579’变成int型 [1,3,5,7,9]
#reduce函数通过fn函数应用到[1,3,5,7,9]上,将[1,3,5,7,9]变成整数13579
13579
filter
filter(function,Iterator)
用途:filter把传入的函数依次作用于每个元素,然后根据返回值是True or False决定保留还是丢弃该元素
例子:埃式筛法,回数
sorted
sortrd(list,function)
用途:将function作用于每一个元素上,并根据function返回的结果进行排序,按照对应关系返回list相应的元素
Key:实现一个映射函数
例子:
#按照字母序排序(因为没有统一大小写的话,会按照ASCII码排序)
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
#反向排序,参数reverse
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
返回函数
函数作为函数值
高阶函数可以将函数作为结果值返回
闭包Closure
在函数A内部又定义了函数B,并且,内部函数B可以引用外部函数A的参数和局部变量,当A返回函数B时,相关参数和变量都保存在返回的函数中
· 闭包返回的函数并没有立即执行,直到调用才开始执行
def lazy_func():
def func():
pass
return func
#得到返回的函数但并没有立即执行
f = lazy_func()
#调用f()才开始执行
f()
· 返回闭包时注意:返回函数不要引用任何循环变量,或者后续会发生变化的变量
· 如果一定要引用循环变量,方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论后续变量如何更改,已绑定到函数参数的值不变。[简单来说,就是在函数内部直接完成调用执行,而不是在外部调用执行,用参数进行绑定]
def count():
def f(i):
def g():
return j*j
return g
fs = []
for i in range(1,4):
fs.append(f(i))
return fs
nonlocal
在内部函数加入 nonlocal x
声明,加入声明之后,解释器将内部函数中的 x 看作外层函数的局部变量
why : 在内部函数直接对外部函数中的变量 赋值 ,解释器会将该变量视为内部函数的局部变量,加入声明后,可以解决该问题
匿名函数
lambda x : x * x
关键字 lambda 表示匿名函数,冒号前的x表示函数参数
匿名函数无需担心函数名冲突
匿名函数是一个函数对象,可以把匿名函数赋值给一个变量,再利用变量来调用该函数
也可以将匿名函数作为返回值返回
def build(x,y):
return lambda: x * x + y * y
装饰器Decorator
在代码运行期间动态增加功能的方式,称为“装饰器”
本质上,decorator就是一个返回函数的高阶函数
# 定义一个能打印日志的decorator
def log(func):
def wrapper(*args,**kw):
print('call %s():' % func._name_)
return func(*args,**kw)
return wrapper
# 借助python的 @ 语法,把decorator置于函数的定义处
@log
def now():
print('2022/10/8')
# 调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前运行log()
>>> now()
call now():
2022/10/8
理解 @log
@log
def now():
=
now = log(now)
# log()是一个装饰器,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数log(now)
# 因此此时调用 now() 将执行新函数,即log()函数中返回的wrapper()函数
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数
# 自定义Log的文本内容
def log(text):
def decorator(func):
def wrapper(*args,**kw):
print('%s %s():' % (text,func.__name__))
return func(*args **kw)
return wrapper
return decorator
# 使用方法
@log('execute')
def now():
print('2022/10/8')
=
now = log('execute')(now)
# 执行(先执行log,再执行now)
>>> now()
execute now()
2022/10/8
经过decorator装饰之后的函数,其name发生变化(一般变成最内层的wrapper),因此需要把原始函数的 __name__
等属性复制到 wrapper()
函数中,否则,有些依赖函数签名的代码执行就会出错
import functools
def log(func):
# 在wrapper定义前,加入下面一行内容,即可将属性复制
@functools.wraps(func)
def wrapper(*args,**kw):
print('call %s():' % func.__name__)
return func(*args,**kw)
return wrapper
偏函数 Partial Function
functools.partial 帮助创建偏函数
import functools
# int('12345') 默认将12345转换成十进制形式的数字
# base参数可以做N进制的转换
# 用函数表达
def int2(x,base=2):
return int(x,base)
# 使用functools.partial表达
int2 = functools.partial(int,base=2)
functools.partial 的作用是:把一个函数的某些参数固定,返回一个新的函数
创建偏函数时,可以接收 函数对象 *args **kw
这三个参数