Python 高阶函数(详解)

        前言:这篇详细讲解了Python中的高阶函数,并且对高阶函数中的重要的内置函数也进行了详解,温馨提醒!篇幅较长可以慢慢观看。

一:高阶函数

只要满足下面的任意一个条件就是高阶函数

  • 1、一个函数的函数名作为参数传给另外一个函数
  • 2、一个函数返回值(return)为另外一个函数(返回为自己,则为递归)
  • 高阶函数的基本概念:

            
    高阶函数是指接受函数作为参数或者返回函数作为结果的函数。它在函数式编程中是一个重要概念(函数式编程(Functional Programming,FP)是一种编程范式,它将计算视为数学函数的求值,并且避免使用可变数据结构和改变状态的操作。函数式编程的核心思想是将函数作为程序的基本构建块,强调不可变性和纯函数的使用)。

    高阶函数与普通函数应用场景的区别:

    普通函数

            普通函数适用于实现具体的、独立的操作,例如数学运算、文件操作、字符串处理等。它们通常具有明确的输入和输出,处理相对具体的任务。

    def square(x):
        return x ** 2

    高阶函数

            高阶函数更具抽象性和通用性,可用于封装通用的算法或操作模式。

    def square(x):
        return x ** 2
    numbers = [1, 2, 3, 4, 5]
    squared_numbers = map(square, numbers)
    def my_sum():
        def new_my_sum():
            print('123')
        return new_my_sum
    
    my_sum = my_sum()

    代码分析(重点,要理解)

            在上面的代码案例中,函数体里面对参数进行了求平方的处理操作,实际情况并不是每个调用者都想对参数进行求绝对值的处理,张三想调用这个函数对参数进行平方处理那怎么办呢?从上面的代码中来看,如果张三想要对参数求平方处理,就不得不把求绝对值的代码改成求平方的代码,如果是这样的话,那这个函数的设计用途就很有限了。那我能不能设计一下,不管调用者想对它进行什么操作,而不用去改变我函数体里面的代码呢?当然可以,这个时候就需要使用函数来作为参数实现了。(高阶函数更灵活,适用的场景也更多)

    def my_sum(a,b,han,hen):
        return han(a)+hen(b)
    
    def dz(shu):
        return shu/2
    
    def da(shu):
        return shu*2
    
    
    print(my_sum(6, 6, da,dz))
    print(my_sum(6,6, da,dz()))

    注意:其中第二个是错误的(不能带括号)

    总结(特别重要):

    1
    、当定义函数时,函数的参数是一个函数,那么定义的这个函数可以称为高阶函数。

    2
    、调用高阶函数时需要特别注意,由于高阶函数中参数类型是个函数,因此在进行调用时,我们只需要传递函数的名字即可,而不是进行函数调用。

    3
    、函数作为参数的类型时,可以是内置的函数,如
    abs
    ,也可以是其它模块下的函数,如sqrt
    ,也可以是自定义的函数,如
    num_num
    ,像上面代码中num_num函数的函数体只有一行代码,可以用
    lambda
    表达式的方式写。

    lambda表达式的多种使用方式:

    def my_sum(a,b,han):
        return han(a)+han(b)
    print(my_sum(6, 6, lambda x:x**2))
    
    def da(shu):
        return shu*2
    f = lambda x,y,z:(z(x),z(y))
    print(f(1, 2, da))

    二:python中内置常用高阶函数

    1.map函数:

    map()
    函数接受一个函数和一个可迭代对象作为参数,将函数应用于可迭代对象的每个元素,并返回一个新的迭代器。

    参数
    1
    :要传入进行处理的函数名

    参数
    2
    :一个可以操作的数据集或者序列或者是可迭代对象

    eg:
    简单点可以理解为:把参数
    2
    中的每个元素拿出来,放到参数
    1
    的函数中去处
    理一遍,再返回到一个新的数据集中去。

    案例:

    # map(函数,可迭代对象):把函数作用于可迭代对象,并且返回可迭代对象
    def fu(a):
        return a*a
    my_list = [1,2,3,4,5]
    print(map(fu,my_list))
    res = map(fu,my_list)
    print(list(res))
    2.reduce函数:

    reduce()
    函数位于
    functools
    模块中,它接受一个函数和一个可迭代对象作为参数,函数必须接受两个参数。reduce()
    会将函数依次应用于可迭代对象的元素,返回一个单一的结果。

    eg:reduce(函数,可迭代对象):函数需要两个参数,返回一个单一结果!

    from functools import reduce
    def fa(x,y):
        # print('x的值为',x)
        # print('y的值为',y)
        return x+y
    my_list = [1,2,3,4,5]
    
    res = (reduce(fa,my_list))
    print(res)
    3.filter函数:

    Python 中,filter() 是一个内置的高阶函数,其主要作用是根据指定的条件过滤可迭代对象中的元素,返回一个包含满足条件元素的迭代器。

    基本语法:

    filter(function, iterable)
  • function:这是一个用于筛选元素的函数,它接受一个参数,并返回一个布尔值(TrueFalse)。如果返回 True,则表示该元素满足条件,会被保留;如果返回 False,则该元素会被过滤掉。这个参数可以是一个普通函数、匿名函数(lambda 函数),也可以为 None
  • iterable:是一个可迭代对象,如列表、元组、字符串、集合等,filter() 函数会对其元素逐个进行筛选。
  • 实例:

    1. 使用普通函数进行筛选
    def is_even(num):
        return num % 2 == 0
    
    numbers = [1, 2, 3, 4, 5, 6]
    even_numbers = filter(is_even, numbers)
    print(list(even_numbers))

    代码解释

  • 定义了一个普通函数 is_even,用于判断一个数是否为偶数。如果是偶数,函数返回 True;否则返回 False
  • 调用 filter(is_even, numbers) 时,filter() 函数会遍历 numbers 列表中的每个元素,并将其传递给 is_even 函数进行判断。
  • 最终,filter() 函数返回一个迭代器,包含了所有偶数元素。使用 list() 函数将迭代器转换为列表并打印,输出结果为 [2, 4, 6]
  • 2. 使用匿名函数(lambda 函数)进行筛选
    numbers = [1, 2, 3, 4, 5, 6]
    even_numbers = filter(lambda x: x % 2 == 0, numbers)
    print(list(even_numbers))

    代码解释

  • 这里使用了一个匿名函数 lambda x: x % 2 == 0 来替代普通函数。匿名函数的功能和上面的 is_even 函数相同,用于判断一个数是否为偶数。
  • filter() 函数的工作方式和前面示例一样,最终返回一个包含偶数元素的迭代器,转换为列表后输出结果同样为 [2, 4, 6]
  • 3. 过滤字符串列表
    words = ["apple", "banana", "cherry", "date"]
    long_words = filter(lambda word: len(word) > 5, words)
    print(list(long_words))

    代码解释

  • 定义了一个字符串列表 words
  • 使用匿名函数 lambda word: len(word) > 5 作为筛选条件,该函数用于判断一个字符串的长度是否大于 5。
  • filter() 函数遍历 words 列表中的每个字符串,并根据匿名函数的返回值进行筛选,最终返回一个包含长度大于 5 的字符串的迭代器,转换为列表后输出结果为 ["banana", "cherry"]
  • 4. 当 function 参数为 None
    values = [0, 1, False, True, [], [1, 2], '', 'hello']
    truthy_values = filter(None, values)
    print(list(truthy_values))

    代码解释

  • function 参数为 None 时,filter() 函数会将 iterable 中的元素转换为布尔值进行判断。在 Python 中,像 0False、空列表 []、空字符串 '' 等会被视为 False,其他值会被视为 True
  • filter() 函数会过滤掉所有被视为 False 的元素,最终返回一个包含被视为 True 的元素的迭代器,转换为列表后输出结果为 [1, True, [1, 2], 'hello']
  • 注意事项

  • 返回值是迭代器filter() 函数返回的是一个迭代器,而不是一个列表。如果需要多次使用筛选结果,或者需要查看所有元素,可以使用 list() 函数将其转换为列表。但要注意,对于大型数据集,将迭代器转换为列表可能会占用大量内存。
  • 原可迭代对象不会被修改filter() 函数只是根据条件筛选元素,不会对原可迭代对象进行修改。
  • 综上所述,filter() 函数是一个非常实用的工具,可以帮助我们方便地根据特定条件筛选可迭代对象中的元素。

    4.sorted函数:

    sorted()
    函数可以对任何可迭代对象进行排序,并返回一个新的列表。它接受一个key
    参数,该参数可以是一个函数,用于指定排序的依据。

    1. 多条件排序

    fr = [
        {'name': 'boa', 'about': 100},
        {'name': 'bob', 'about': 200},
        {'name': 'boc', 'about': 300},
    ]
    def fr_my(x):
        return -x['about'],x['name']
    
    print(sorted(fr, key=fr_my))
    
    students = [
        {"name": "Alice", "age": 20},
        {"name": "Bob", "age": 18},
        {"name": "Charlie", "age": 20}
    ]
    sorted_students = sorted(students, key=lambda student: (student["age"], student["name"]))
    print(sorted_students)

    代码解释: 这里的 key 函数返回一个元组 (student["age"], student["name"]),表示先按 "age" 进行排序,如果 "age" 相同,则按 "name" 进行排序。最终输出结果为 [{'name': 'Bob', 'age': 18}, {'name': 'Alice', 'age': 20}, {'name': 'Charlie', 'age': 20}]

    2. 自定义排序规则(例如按绝对值排序)

    numbers = [-3, 1, -2, 4]
    sorted_numbers = sorted(numbers, key=abs)
    print(sorted_numbers)

     代码解释: 指定 key 函数为 abs(求绝对值的函数),sorted() 函数会根据每个数的绝对值进行排序,输出结果为 [1, -2, -3, 4]

    注意事项

  • 返回值是新列表sorted() 函数会返回一个新的已排序列表,原可迭代对象不会被修改。如果需要对原列表进行原地排序,可以使用列表的 sort() 方法。
  • 元素类型一致性:在排序时,要确保 iterable 中的元素类型是可以相互比较的,否则可能会引发 TypeError 异常。例如,不能直接对包含数字和字符串的列表进行排序。
  • 综上所述,sorted() 函数是一个非常强大且灵活的排序工具,通过合理使用 keyreverse 参数,可以满足各种不同的排序需求。

    5.any函数和all函数:

    any() 函数接受一个可迭代对象(如列表、元组、集合、字符串等)作为参数,用于检查可迭代对象中是否至少有一个元素的布尔值为 True

    工作原理(相当于or)

  • any() 函数会遍历可迭代对象中的每个元素。
  • 对于每个元素,将其转换为布尔值(使用 bool() 函数)。
  • 如果在遍历过程中遇到一个元素的布尔值为 True,则函数立即返回 True,不再继续遍历后续元素。
  • 如果遍历完整个可迭代对象后,没有找到布尔值为 True 的元素,则函数返回 False
  • 示例代码:

    # 示例 1:列表中至少有一个元素为 True
    numbers = [0, False, 3]
    result = any(numbers)
    print(result)  # 输出: True,因为 3 转换为布尔值为 True
    
    # 示例 2:列表中所有元素都为 False
    empty_list = []
    false_list = [0, False, '']
    print(any(empty_list))  # 输出: False,空列表中没有元素为 True
    print(any(false_list))  # 输出: False,列表中所有元素转换为布尔值都为 False
    
    # 示例 3:字符串
    string = "abc"
    print(any(string))  # 输出: True,因为字符串中的每个字符转换为布尔值都为 True
    
    # 示例 4:嵌套可迭代对象
    nested_list = [[], [0], [False]]
    print(any(nested_list))  # 输出: True,因为 [0] 转换为布尔值为 True

    all() 函数同样接受一个可迭代对象作为参数,用于检查可迭代对象中的所有元素的布尔值是否都为 True

    工作原理(相当于and)

  • all() 函数会遍历可迭代对象中的每个元素。
  • 对于每个元素,将其转换为布尔值(使用 bool() 函数)。
  • 如果在遍历过程中遇到一个元素的布尔值为 False,则函数立即返回 False,不再继续遍历后续元素。
  • 如果遍历完整个可迭代对象后,所有元素的布尔值都为 True,则函数返回 True。需要注意的是,对于空的可迭代对象,all() 函数会返回 True
  • 示例代码:

    # 示例 1:列表中所有元素都为 True
    numbers = [1, True, 'abc']
    result = all(numbers)
    print(result)  # 输出: True,因为列表中所有元素转换为布尔值都为 True
    
    # 示例 2:列表中有元素为 False
    mixed_list = [1, 0, True]
    print(all(mixed_list))  # 输出: False,因为 0 转换为布尔值为 False
    
    # 示例 3:空列表
    empty_list = []
    print(all(empty_list))  # 输出: True,空列表视为所有元素都为 True
    
    # 示例 4:字符串
    string = "abc"
    print(all(string))  # 输出: True,因为字符串中的每个字符转换为布尔值都为 True
    
    # 示例 5:嵌套可迭代对象
    nested_list = [[1], [2], [3]]
    print(all(nested_list))  # 输出: True,因为每个子列表转换为布尔值都为 True

    总结

  • any() 函数用于判断可迭代对象中是否至少有一个元素的布尔值为 True
  • all() 函数用于判断可迭代对象中的所有元素的布尔值是否都为 True,空可迭代对象也视为所有元素都为 True
  • 这两个函数在处理条件判断和逻辑检查时非常有用,可以避免手动编写复杂的循环来检查元素的布尔值。

    6.zip函数:

    *iterables 表示可以传入任意数量的可迭代对象,这些可迭代对象将被 “压缩” 在一起。

    工作原理

  • zip() 函数会从每个传入的可迭代对象中依次取出一个元素,组成一个元组,然后将这些元组作为新的迭代器的元素。
  • 当最短的可迭代对象元素被取完时,zip() 函数就会停止迭代,即使其他可迭代对象还有剩余元素。
  • 1.压缩多个可迭代对象
    list1 = [1, 2, 3]
    list2 = ['a', 'b', 'c']
    tuple1 = (10, 20, 30)
    zipped = zip(list1, list2, tuple1)
    print(zipped)            #输出地址
    print(list(zipped))      

    代码解释

  • 这次传入了三个可迭代对象:list1list2tuple1
  • zip() 函数会从这三个可迭代对象中依次取出对应位置的元素,组成三元组。
  • 输出结果为 [(1, 'a', 10), (2, 'b', 20), (3, 'c', 30)]
  • 2.结合 for 循环使用
    names = ['Alice', 'Bob', 'Charlie']
    ages = [25, 30, 35]
    for name, age in zip(names, ages):
        print(f"{name} is {age} years old.")

    代码解释

  • zip(names, ages) 会生成一个迭代器,其中每个元素是一个包含姓名和年龄的元组。
  • for 循环会依次从这个迭代器中取出元组,并将元组中的元素分别赋值给 nameage 变量。
  • 最终会依次输出每个人员的姓名和年龄信息。
  • 3.解压缩操作
    pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
    numbers, letters = zip(*pairs)
    print(numbers)
    print(letters)

    代码解释

  • *pairs 是将 pairs 列表中的元素解包作为参数传递给 zip() 函数。
  • zip() 函数会对这些元组进行 “解压缩” 操作,将每个元组中相同位置的元素重新组合成新的元组。
  • 最终 numbers(1, 2, 3)letters('a', 'b', 'c')
  • 注意事项

  • 最短可迭代对象原则zip() 函数会以最短的可迭代对象为准停止迭代。
  • 返回的是迭代器zip() 函数返回的是一个迭代器,而不是列表。如果需要多次使用结果或者查看所有元素,可以使用 list() 函数将其转换为列表,但要注意对于大型数据集,将迭代器转换为列表可能会占用大量内存。
  • 综上所述,zip() 函数是一个非常方便的工具,在处理多个可迭代对象时,可以轻松地将它们的元素进行组合或解组合。

    7.enumerate函数:

    在 Python 中,enumerate() 是一个实用的高阶函数,常用于在遍历可迭代对象(如列表、元组、字符串等)时同时获取元素的索引和对应的值。

    enumerate(iterable, start=0)
  • iterable:必需参数,代表要进行遍历的可迭代对象,例如列表、元组、字符串等。
  • start:可选参数,是一个整数,用于指定索引的起始值,默认值为 0
  • 工作原理

  • enumerate() 函数会接收一个可迭代对象,并返回一个枚举对象,该枚举对象是一个迭代器。
  • 在迭代过程中,每次迭代会生成一个包含两个元素的元组,第一个元素是当前元素的索引(从 start 指定的值开始),第二个元素是可迭代对象中对应位置的元素。
  • 1.指定索引起始值:
    fruits = ['apple', 'banana', 'cherry']
    for index, fruit in enumerate(fruits, start=1):
        print(f"第 {index} 个水果是: {fruit}")
    2.使用enumerate()函数可以很方便地同时获取元素的索引和元素本身。例如,在需要打印列表元素及其位置的时候
    fruits = ["apple", "banana", "cherry"]
    for index, fruit in enumerate(fruits):
        print(f"Index {index}: {fruit}")
    3.用于构建字典:可以利用enumerate()函数来构建字典,其中索引作为键,可迭代对象中的元素作为值。
    fruits = ["apple", "banana", "cherry"]
    fruit_dict = dict(enumerate(fruits))
    print(fruit_dict)

    注意事项

  • 返回的是迭代器enumerate() 函数返回的是一个枚举对象,它是一个迭代器。如果需要多次使用结果或者查看所有元素,可以使用 list() 函数将其转换为列表,但要注意对于大型数据集,将迭代器转换为列表可能会占用大量内存。
  • 索引是从 start 开始的:要注意根据实际需求设置 start 参数的值,避免索引使用错误。
  • 综上所述,enumerate() 函数是一个非常方便的工具,在需要同时获取可迭代对象元素的索引和值时,能大大简化代码的编写。

    8.labmda函数:

    lambda函数是一种匿名函数,可以用于创建简单的函数对象,通常用于高阶函数的参数。

    基本语法
    lambda arguments: expression
  • lambda:这是定义 lambda 函数的关键字。
  • arguments:表示函数的参数,可以是零个或多个参数,多个参数之间用逗号分隔。
  • expression:是一个表达式,该表达式的计算结果就是函数的返回值。lambda 函数只能包含一个表达式,不能包含复杂的语句,如 iffor 等。
  • 特点
    1. 简洁性lambda 函数的定义通常很简短,适合用于编写简单的函数逻辑,能让代码更加简洁。
    2. 匿名性:它没有像普通函数那样的显式名称,通常作为参数传递给其他高阶函数使用,使用完后不会在命名空间中保留函数名。
    3. 一次性使用:由于其简洁性和匿名性,lambda 函数常用于临时需要一个小函数的场景,用完即弃。

    numbers = [1, 2, 3, 4, 5]
    squared_numbers = list(map(lambda x: x ** 2, numbers))
    print(squared_numbers)
    对比总结
  • 语法复杂度:普通函数需要使用 def 关键字、函数名、参数列表、冒号、缩进等,语法相对复杂;而 lambda 函数语法简洁,一行即可定义。
  • 功能复杂性:普通函数可以包含复杂的语句和逻辑,如 if 语句、for 循环等;lambda 函数只能包含一个表达式,功能相对简单。
  • 命名和复用性:普通函数有明确的名称,可以在代码中多次调用,具有较高的复用性;lambda 函数通常是匿名的,主要用于一次性的简单操作。
  • 注意事项
  • 表达式限制lambda 函数只能包含一个表达式,不能包含语句。如果需要实现复杂的逻辑,建议使用普通函数。
  • 可读性:虽然 lambda 函数简洁,但如果表达式过于复杂,会降低代码的可读性。在这种情况下,使用普通函数可能更好。
  • 综上所述,lambda 函数是 Python 中一种非常有用的工具,在需要简单函数逻辑且不需要复用的场景下,能让代码更加简洁高效。

                                                  好啦Python中的高阶函数就讲到这里拉

    作者:坦率的小新

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python 高阶函数(详解)

    发表回复