Python 高阶函数(详解)
前言:这篇详细讲解了Python中的高阶函数,并且对高阶函数中的重要的内置函数也进行了详解,温馨提醒!篇幅较长可以慢慢观看。
一:高阶函数
只要满足下面的任意一个条件就是高阶函数
- 1、一个函数的
函数名
作为参数传给另外一个函数 - 2、一个函数返回值(return)为另外一个
函数
(返回为自己,则为递归)
高阶函数的基本概念:
高阶函数与普通函数应用场景的区别:
普通函数:
普通函数适用于实现具体的、独立的操作,例如数学运算、文件操作、字符串处理等。它们通常具有明确的输入和输出,处理相对具体的任务。
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 :一个可以操作的数据集或者序列或者是可迭代对象
# 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
:这是一个用于筛选元素的函数,它接受一个参数,并返回一个布尔值(True
或False
)。如果返回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 中,像0
、False
、空列表[]
、空字符串''
等会被视为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()
函数是一个非常强大且灵活的排序工具,通过合理使用 key
和 reverse
参数,可以满足各种不同的排序需求。
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))
代码解释:
- 这次传入了三个可迭代对象:
list1
、list2
和tuple1
。 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
循环会依次从这个迭代器中取出元组,并将元组中的元素分别赋值给name
和age
变量。- 最终会依次输出每个人员的姓名和年龄信息。
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
函数只能包含一个表达式,不能包含复杂的语句,如if
、for
等。
特点
- 简洁性:
lambda
函数的定义通常很简短,适合用于编写简单的函数逻辑,能让代码更加简洁。 - 匿名性:它没有像普通函数那样的显式名称,通常作为参数传递给其他高阶函数使用,使用完后不会在命名空间中保留函数名。
-
一次性使用:由于其简洁性和匿名性,
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中的高阶函数就讲到这里拉