一、什么是高阶函数
1.1、高阶函数的概念和作用:
高阶函数是指 接受函数作为参数 或者 返回函数 作为结果的函数。它在函数式编程中是一个重要概念(函数式编程(Functional Programming , FP )是一 种编程范式,它将计算视为数学函的求值,并且避免使用可变数据结构和 改变状态的操作。函数式编程的核心思想是将函数作为程序的基本构建块, 强调不可变性和纯函数的使用)。
1.2、高阶函数的特点:
(1)、接受一个或多个函数作为输入参数:这意味着你可以将函数作为参数传 递给另一个函数。
(2)、返回一个函数作为输出:这意味着函数可以返回另一个函数。
二、当参数为一个函数的情况
案例:
# 需求:定义一个函数,带两个整数类型的参数
# 该函数的功能是把两个 参数整理之后 做求和计算,并把结果返回
非高阶函数的写法:
def my_function(num1,num2):# 对传入的两个参数进行平方处理new_num1 = num1**2new_num2 = num2**2# 对处理后的文件进行求和操作,并返回return new_num1+new_num2
print(my_function(3,4))
非高阶函数写法的弊端:
由于题目的需求的不确定性,针对于“参数整理之后”没有明确的规定,在上面的案例中,我们对传入的两个参数进行了平方再求和的操作,但是实际上有些时候,我们不同的用户调用函数时可能进行不同的处理,比如张三要对这两个数字求绝对值再求和呢?就不得吧求平方的代码改为求绝对值的代码,这样的话函数的用途就很有限了。那么我们怎么样设计才能够不管调用者想对他进行什么操作,而不用改变函数体内的代码呢,当然可以,这个时候我们就需要使用函数作为参数实现了。
高阶函数的写法:
1、当行为函数是自定义时:
# 定义行为函数
def do_function(number):return number * 10
# 注意:在参数中传入函数时不需要加(),加上小括号,表示的是调用函数,不是参数
def my_function(num1,num2,function):""":param num1: 传入第一个数字的参数:param num2: 传入第二个数字的参数:param function: 传入你想要进行的函数操作:return: 返回值是对传入的数字进行处理后求和计算"""return function(num1) + function(num2)
# 调用函数:调用函数在传入函数时不需要加(),加上小阔号表示的是调用函数,不是传参
print(my_function(1,2,do_function))
2、当行为函数是内置模块的函数时:
def my_function(num1,num2,function):""":param num1: 传入第一个数字的参数:param num2: 传入第二个数字的参数:param function: 传入你想要进行的函数操作:return: 返回值是对传入的数字进行处理后求和计算"""return function(num1) + function(num2)# 导入math模块进行先求根再进行操作
import math
# 对参数进行求平方根再求和
print(my_function(100, 4, math.sqrt))
# 对参数进行阶乘操作后求和
print(my_function(2, 4, math.factorial))
3、传入的函数只有一句话时:可以使用lambda表达式:
# 刚刚求和的函数:
my_function = lambda num1, num2,function: function(num1) + function(num2)
# 行为参数:
do_function = lambda number: number * number
# 调用函数并输出
print(my_function(1, 2, do_function))
4、总结:
(1)、当定义函数时,函数的参数是一个函数,那么定义的这个函数可以称为 高阶函数。
(2)、调用高阶函数时需要特别注意,由于高阶函数中参数类型是个函数,因此在进行调用时,我们只需要传递函数的名字即可,而不是进行函数调用。
(3)、函数作为参数的类型时,可以是内置的函数,如abs ,也可以是其它模块 下的函数,如sqrt ,也可以是自定义的函数,如 num_num ,像上面代码中 num_num函数的函数体只有一行代码,可以用 lambda 表达式的方式写。
5、当参数有两个函数时:
# 传入math模块
import math
# 定义高阶函数
def self_fuc(num1,num2,function1,function2):
# 对第一个参数乘10,对第二个参数阶乘操作,再求和return function1(num1) + function2(num2)
# 调用函数:传入两个行为函数
print(self_fuc(1, 2, lambda x: x * 10, math.factorial))
三、当返回值是一个函数的时候
def out_function(*args):print("我是外部函数!")def inner_function(number):sum = 0for i in args:sum += iprint("我是内部函数里面的number,传入的值为:",number)return f'累加结果为:{sum}'# 返回值为内部函数,不需要加(),加上表示调用函数return inner_function
# 返回为地址:因为返回的内部函数的名字,打印的为地址
print(out_function(2,3,4))
# 外部函数返回为内部函数的inner_function,后面的括号表示的inner_function(666)
print(out_function(2,3,4)(666))
四、常见的Python内置高阶函数
4.1、map函数
map() 函数 接受一个函数 和 一个可迭代对象 作为参数,将函数应用于可迭代 对象的每个元素,并 返回一个新的迭代器 。
参数 1 :要传入进行处理的函数名
参数 2 :一个可以操作的数据集或者序列或者是可迭代对象
简单点可以理解为:把参数 2 中的每个元素拿出来,放到参数 1 的函数中去处 理一遍,再返回到一个新的数据集中去。
案例:
# 导入math模块
import math
# 定义一个可迭代数据
numbers = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 调用高阶函数map()并且传入参数,使用sqrt函数对每个数据求算数平方根
map_res = map(math.sqrt, numbers)
print(map_res)
# 由于map函数返回是一个迭代器对象,直接打印的话不够直观
# 因此使用list函数给它进行转化一下输出更直观
print(list(map_res))
4.2、reduce函数
reduce() 函数位于 functools 模块中,它接受 一个函数 和一个 可迭代对 象 作为参数, 函数必须接受两个参数 。reduce() 会将函数依次应用于可迭代 对象的元素, 返回一个单一的结果 。
# 导入包
import functools
def my_fc(x,y):print("x的值:",x)print("y的值:",y)return x + y
# 定义要操作的可迭代数据
my_list = [1,2,3,4,5]
# 调用reduce函数
res = functools.reduce(my_fc,my_list)
print(res)
4.3、filter函数
filter() 函数接受一个函数和一个可迭代对象作为参数。 filter() 会 过滤 掉那些函数返回False 的元素,返回一个新的迭代器
# 定义行为参数
def my_function(x):if x > 10:return x
# 定义要处理的可迭代数据
num_list = [1,2,3,4,5,10,20,30,40,50]
# 调用filter函数
res = filter(my_function, num_list)
print(list(res))
4.4、sorted函数
sorted() 函数可以对任何可迭代对象进行排序,并返回一个新的列表。它接受一个key 参数,该参数可以是一个函数,用于指定排序的依据。
stu = [{"name" : "jack","age" : 20},{"name" : "tom","age" : 19},{"name" : "lucy","age" : 19},
]
# 先根据年龄排序,如果年龄相同,再根据名字排序
new_stu = sorted(stu, key=lambda x:(x["age"],x["name"]),reverse=True)
print(new_stu)
4.5、any函数和all函数
any() :如果可迭代对象中至少有一个元素为 True ,则返回 True 。
all() :如果可迭代对象中所有元素都为 True ,则返回 True 。
numbers = [1,2,3,4,5,0]
# 是否有非0元素:
is_true = any(numbers)
print(is_true)
# 是否没有0元素
is_true1 = all(numbers)
print(is_true1)
4.6、zip函数
zip() 函数接受多个可迭代对象作为参数,将它们组合成一个迭代器,每个元素是一个元组,包含来自每个可迭代对象的对应元素。
names = ("李小妹","帅哥","张三","tom")
ages = [23,24,20]
# 组合成一个列表
res = list(zip(names,ages))
print(res)
# 组合成一个字典
res1 = dict(zip(names,ages))
print(res1)
# 组合成一个元组
res2 = tuple(zip(names,ages))
print(res2)# 如果合成后还有一个可迭代对象的元素没有匹配,那么将会自动舍弃
4.7、enumerate函数
enumerate() 函数接受一个可迭代对象和一个可选的起始索引,返回一个迭代器,每个元素是一个元组,包含索引和对应的值。
names = ["李小妹","帅哥","张三","tom"]
res = enumerate(names,start=0)
# 只能转化为list
print(list(res))
print(dict(res))
print(tuple(res))
print(set(res))
五、高阶函数的练习
假设你是一家电商公司的数据分析师,需要对销售数据进行分析。你有一个 包含多个订单信息的列表,每个订单信息是一个字典,包含订单ID 、客户ID、订单金额和订单日期。你需要完成以下任务:
1. 筛选出订单金额大于 1000 元的订单 。
2. 计算每个订单的折扣金额(折扣率为 10% ) 。
3. 计算所有订单的总金额 。
4. 找出订单金额最高的订单 。
任务要求:
1. 筛选出订单金额大于 1000 元的订单 :
使用 filter 函数筛选出订单金额大于 1000 元的订单。
将结果存储在变量 high_value_orders 中。
2. 计算每个订单的折扣金额(折扣率为 10% ) :
使用 map 函数计算每个订单的折扣金额。
将结果存储在变量 discounted_orders 中,每个订单字典中增加
一个 discount 键,值为折扣金额。
3. 计算所有订单的总金额 :
使用 map 函数提取所有订单的金额。
使用 reduce 函数计算所有订单的总金额。
将结果存储在变量 total_amount 中。
4. 找出订单金额最高的订单 :
使用 max 函数和 key 参数找出订单金额最高的订单。
将结果存储在变量 highest_amount_order 中。
from functools import reduce
# 数据
orders = [{"order_id": 1, "customer_id": 101, "amount": 1200,"date": "2024-01-01"},{"order_id": 2, "customer_id": 102, "amount": 800,"date": "2024-01-02"},{"order_id": 3, "customer_id": 103, "amount": 1500,"date": "2024-01-03"},{"order_id": 4, "customer_id": 104, "amount": 950,"date": "2024-01-04"},{"order_id": 5, "customer_id": 105, "amount": 1800,"date": "2024-01-05"}
]
# 1. 筛选出订单金额大于1000元的订单
high_value_orders = list(filter(lambda order:
order["amount"] > 1000, orders))
# 2. 计算每个订单的折扣金额(折扣率为10%)
discounted_orders = list(map(lambda order: {**order,
"discount": order["amount"] * 0.1}, orders))
# 3. 计算所有订单的总金额
amounts = list(map(lambda order: order["amount"], orders))
total_amount = reduce(lambda x, y: x + y, amounts)
# 4. 找出订单金额最高的订单
highest_amount_order = max(orders, key=lambda order:
order["amount"])
# 输出结果
print("订单金额大于1000元的订单:", high_value_orders)
print("每个订单的折扣金额:", discounted_orders)
print("所有订单的总金额:", total_amount)
print("订单金额最高的订单:", highest_amount_order)
六、递归函数的引入
如果一个函数在执行过程中调用自身,那么这个函数就可以称为递归函数。 也就是在函数体中调用自己。
递归函数的特点:
1 、函数体中调用自己
2 、有一个条件作为出口。不然一直自己调用自己层层套下去就成死循环 了,所以必须要有个条件终止。
阶乘案例:、
def fbnq(n):if n == 1:return 1else:return n * fbnq(n-1)
print(fbnq(4))