高阶函数
将函数 a
作为变量传给另一个函数 b
,函数 b
就是一个高阶函数。
def b(a):
num = 2 - 5
return a(num)
a = abs
result = b(a)
print(result) # 3
Python 内置的高阶函数中,有几个很常用。
map()
函数。
如果想要将一个可迭代对象中的元素全部按照某种规则修改,就可以用 map()
。
map()
的用法为:map(func, iter)
:
- func:是一个函数,表示规则
- iter:是可迭代对象
比如想要把列表 [1, 2, 3]
的元素全部乘 2,可以这样写:
demo_list = [1, 2, 3]
result = map(lambda x: x * 2, demo_list)
print(list(result)) # [2, 4, 6]
map()
返回迭代器,常与lambda
配合使用。
reduce()
函数
reduce()
描述起来不太直观,直接看示例。
reduce()
的用法为:reduce()
:
- func:是一个接收两个参数的函数,表示规则
- iter:是可迭代对象
比如给出一个列表,想要求和:[1, 2, 3, 4]
。
from functools import reduce
demo_list = [1, 2, 3, 4]
result = reduce(lambda x, y: x + y, demo_list)
print(result) # 10
在这个例子中,先把
1
和2
分别作为x
和y
,其返回值和后一个元素3
分别作为下一个x
和y
,按照这样递归的模式一直执行,直到迭代完成,返回结果。
reduce 也可配合lambda
使用。
reduce()
结合 map()
可以写一个将字符串转为整型的算法。
from functools import reduce
STR_2_INT_MAP = {
"0" : 0,
"1" : 1,
"2" : 2,
"3" : 3,
"4" : 4,
"5" : 5,
"6" : 6,
"7" : 7,
"8" : 8,
"9" : 9,
}
demo_str = "12345"
result = reduce(
lambda a, b : a * 10 + b,
map(
lambda x : STR_2_INT_MAP[x],
demo_str
)
)
print(result) # 12345
filter()
函数
filter()
可以从可迭代对象中筛选出符合给定的规则的元素,返回生成器。
写法:filter(func, iter)
- func:是一个函数,表示规则
- iter:可迭代对象
比如筛选出 [1, 2, 3, 4, 5, 6, 7]
中的偶数:
demo_list = [1, 2, 3, 4, 5, 6, 7]
result = filter(
lambda x: x % 2 == 0,
demo_list
)
print(list(result)) # [2, 4, 6]
sorted()
函数
写法:sorted(iter, key, reverse)
- iter:可迭代对象
- key:是一个函数,排序的规则,这个参数是内置的
- reverse:是否反转,这个参数是内置的
比如要得到 [3, 6, 3, 8, 9, 6, 7, 1]
排序后的结果:
demo_list = [3, 6, 3, 8, 9, 6, 7, 1]
result = sorted(demo_list)
print(result) # [1, 3, 3, 6, 6, 7, 8, 9]
sorted()
与sort()
不同,
sorted(demo_list)
返回一个新列表,内容是排序的结果,
demo_list.sort()
是直接改变了demo_list
,且没有返回值。
闭包
闭包实质上就是函数里面再写个函数,然后把子函数作为返回值,子函数的数量无限制。
一个常规的求和函数可以是这样:
def get_sum(nums):
result = 0
for num in nums:
result += num
return result
nums = [1, 2, 3, 4, 5]
result = get_sum(nums)
print(result) # 15
将这个求和函数改成懒加载的形式:
def get_sum(nums):
def inner_sum():
result = 0
for num in nums:
result += num
return result
return inner_sum
nums = [1, 2, 3, 4, 5]
func_result = get_sum(nums)
print(func_result) # <function get_sum.<locals>.inner_sum at 0x7fc11311e940>
print(func_result()) # 15
闭包中的子函数引用的是变量,而不是变量的值。比如下面这个闭包:
def square():
result = []
for num in [1, 2, 3]:
def sq():
return num * num
result.append(sq)
return result
re1, re2, re3 = square()
print(re1) # <function square.<locals>.sq at 0x7fc11272a700>
print(re2) # <function square.<locals>.sq at 0x7fc11272aca0>
print(re3) # <function square.<locals>.sq at 0x7fc11272a940>
"""
这三个函数引用中,引用的是 num * num 这个变量,不是值
当循环结束后,num 已经都变成了 3,所以全部返回 9。
"""
print(re1()) # 9
print(re2()) # 9
print(re3()) # 9
如果一定要引用值,就要再加一层子函数:
def square():
def sq(num):
def sq_value():
return num * num
return sq_value
result = []
for num in [1, 2, 3]:
result.append(
sq(num)
)
return result
re1, re2, re3 = square()
print(re1) # <function square.<locals>.sq.<locals>.sq_value at 0x7fc1127d5ca0>
print(re2) # <function square.<locals>.sq.<locals>.sq_value at 0x7fc1127d5940>
print(re3) # <function square.<locals>.sq.<locals>.sq_value at 0x7fc1127d5430>
print(re1()) # 1
print(re2()) # 4
print(re3()) # 9
装饰器
装饰器可以在不改变函数逻辑的情况下,增加一些功能。比如给出一个求和函数:
def get_sum():
nums = [1, 2, 3, 4, 5]
result = 0
for num in nums:
result += num
return result
result = get_sum()
print(result) # 15
现在如果要在运行这个函数的开始打印日志,就可以另写一个函数 dec_get_sum()
,然后在 get_sum()
头上加 @dec_get_sum
实现装饰器的效果。
def dec_get_sum(func):
def wrapper(*args, **kwargs): # 形参写作 *args, **kwargs,表示接受任何参数
print(
f"开始求和...函数名称为:{func.__name__}" # func.__name__ 可以拿到函数的名称
)
return func(*args, **kwargs)
return wrapper
@dec_get_sum
def get_sum():
nums = [1, 2, 3, 4, 5]
result = 0
for num in nums:
result += num
return result
result = get_sum()
print(result)
"""
开始求和...函数名称为:get_sum
15
"""
给函数加装饰器 @dec_get_sum
等效于执行:get_sum = dec_get_sum(get_sum)
。
如果要自定义日志的内容,装饰器函数就需要在外面再套一层:
import functools
def print_log(text):
def dec_get_sum(func):
@functools.wraps(func)
def wrapper(*args, **kwargs): # 形参写作 *args, **kwargs,表示接受任何参数
print(
f"开始求和...当前时间为:{text},函数名称为:{func.__name__}" # func.__name__ 可以拿到函数的名称
)
return func(*args, **kwargs)
return wrapper
return dec_get_sum
import time
@print_log(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
def get_sum():
nums = [1, 2, 3, 4, 5]
result = 0
for num in nums:
result += num
return result
result = get_sum()
print(result)
"""
开始求和...当前时间为:2021-09-07 11:44:21,函数名称为:get_sum
15
"""
print(get_sum.__name__) # 'wrapper'
@print_log("text")
的实质是:get_sum = print_log("text")(get_sum)
。
这时如果打印一下 get_sum
的 __name__
,发现函数名称已经被改变了,需要用一个内置的方法修正:functools.wraps(func)
。修改后的代码如下:
import functools
def print_log(text):
def dec_get_sum(func):
@functools.wraps(func)
def wrapper(*args, **kwargs): # 形参写作 *args, **kwargs,表示接受任何参数
print(
f"开始求和...当前时间为:{text},函数名称为:{func.__name__}" # func.__name__ 可以拿到函数的名称
)
return func(*args, **kwargs)
return wrapper
return dec_get_sum
import time
@print_log(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
def get_sum():
nums = [1, 2, 3, 4, 5]
result = 0
for num in nums:
result += num
return result
result = get_sum()
print(result)
"""
开始求和...当前时间为:2021-09-07 11:50:59,函数名称为:get_sum
15
"""
print(get_sum.__name__) # get_sum
偏函数
想要改变函数的某个参数的默认值,作为一个新函数,这时就可以用偏函数。
比如对于内置的 int()
函数:
int()
函数实质为:指定参数的进制,返回其 10
进制,可以用 base
指定当前参数的进制。
print(int("123")) # 123,base 默认为10,0 也是十进制
print(int("123", base=2)) # 报错,因为123不是二进制数
print(int("010101", base=2)) # 21
定义一个二进制转十进制的函数
import functools
bin_2_dec = functools.partial(int, base=2)
print(bin_2_dec("010101")) # 21
(本文完)