一、什么是高阶函数
1.1、高阶函数的概念和作用:
 
         高阶函数是指 
 接受函数作为参数 
 或者 
 返回函数 
 作为结果的函数。它在函数式编程中是一个重要概念(函数式编程(Functional Programming 
 , 
 FP 
 )是一 种编程范式,它将计算视为数学函的求值,并且避免使用可变数据结构和 改变状态的操作。函数式编程的核心思想是将函数作为程序的基本构建块, 强调不可变性和纯函数的使用)。 
 
1.2、高阶函数的特点:
(1)、接受一个或多个函数作为输入参数:这意味着你可以将函数作为参数传 递给另一个函数。
(2)、返回一个函数作为输出:这意味着函数可以返回另一个函数。
二、当参数为一个函数的情况
案例:
 
 #  
 需求:定义一个函数,带两个整数类型的参数 
 
 
 #  
 该函数的功能是把两个 
 参数整理之后 
 做求和计算,并把结果返回 
 
 
  非高阶函数的写法: 
 
def my_function(num1,num2):
    # 对传入的两个参数进行平方处理
    new_num1 = num1**2
    new_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 = 0
        for i in args:
            sum += i
        print("我是内部函数里面的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 1
    else:
        return n * fbnq(n-1)
print(fbnq(4))



















