在 Python 中,函数是 「头等公民」(first-class),也就是说,函数与其他数据类型(如 int)处于平等地位。因而,我们可以将函数赋值给变量,也可以将其作为参数传入其他函数,将它们存储在其他数据结构(如dicts
)中,并将它们作为其他函数的返回值。
高阶函数
接受函数作为输入或返回函数的函数叫做高阶函数,它是函数式编程的重要组成部分。我们来看一个例子,假设我们想对一个项目列表执行迭代,并将其顺序打印出来,我们可以轻松构建一个如下所示的函数:
def iterate(list_of_items): for item in list_of_items: print(item)
这看起来很简单,但这只不过是一级抽象而已,如果我们想在对列表执行迭代时进行打印以外的其他操作要怎么做呢?这就是高阶函数存在的意义。我们可以创建一个函数 iterate_custom
,待执行迭代的列表和要对每个项应用的函数都是 iterate_custom
函数的输入:
def iterate_custom(list_of_items, custom_func): # custom_func 是一个函数 for item in list_of_items: custom_func(item)
上面的 iterate_custom
就是一个高阶函数了,我们将 custom_func
函数作为参数传递给 iterate_custom
函数,这看起来也很简单,但其实非常强大。
我们已经把抽象的级别提高了一层,使代码具备更强的可重用性。现在,我们不仅可以在打印列表时调用该函数,还可以对涉及序列迭代的列表执行任意操作。
函数还能被返回,从而使事情变得更加简单,例如:
def add(x, y): return x + y def sub(x, y): return x - y def mult(x, y): return x * y def calculator(opcode): if opcode == 1: return add elif opcode == 2: return sub else: return mult my_calc = calculator(2) # my calc is a subtractor my_calc(5, 4) # returns 5 - 4 = 1 my_calc = calculator(9) # my calc is now a multiplier my_calc(5, 4) # returns 5 x 4 = 20.
在上面的代码中,calculator
函数根据传入的 opcode
返回不同的函数,这样我们就可以根据不同的 opcode
执行不同的操作。比如 calculator(2)
返回的是 sub
函数,calculator(9)
返回的是 mult
函数,然后我们就可以调用这些函数进行计算。
匿名函数(lambda)
匿名函数是一种简洁的函数定义方式,使用 lambda
关键字,不需要使用 def
定义函数名,lambda
函数的定义语法如下:
lambda arguments: expression
其中 arguments
表示函数的参数,可以是一个或多个参数,用逗号分隔。expression
表示函数的返回值,可以是任意表达式。
比如下面的例子,我们定义了一个匿名函数,用于计算两个数的和:
# 普通函数 def add(x, y): return x + y # 匿名函数 add_lambda = lambda x, y: x + y print(add_lambda(3, 5)) # 输出: 8
lambda
表达式用于定义简洁的匿名函数,适合用于高阶函数的参数。
常见高阶函数
Python 内置了很多高阶函数,比如 map
、filter
和 reduce
等,它们可以帮助我们更方便地处理数据,下面我们来看看几个常见高阶函数的用法。
max() / min()
max()
/ min()
除了按元素本身比较外,还支持通过 key
指定一个函数,按元素总的某项值进行比较。这个函数满足以下要求:
- 参数是序列的一项
- 返回一个可比较类型(如字符串、数字等)
# 获取列表最大值/最小值 data = [1, 10, 5, 7, 6] print(max(data)) print(min(data)) # 获取字典列表中某个字段最大值 data = [ {'name': '张三', 'gender': 'male', 'age': 27, 'score': 88}, {'name': '李四', 'gender': 'female', 'age': 21, 'score': 66}, {'name': '王五', 'gender': 'male', 'age': 24, 'score': 73}, {'name': '赵六', 'gender': 'female', 'age': 20, 'score': 92}, {'name': '孙七', 'gender': 'female', 'age': 22, 'score': 80}, ] # max() 支持按用户指定函数(规则),求最大值 print('年龄最大的', max(data, key=lambda x: x['age'])) # min() 支持按用户指定函数(规则),求最小值 print('分数最低的', min(data, key=lambda x: x['score']))
max
和 min
函数可以获取列表中的最大值和最小值,但是如果这个列表不是简单的数字列表,而是一个字典列表,我们可以通过 key
参数指定一个函数,按照这个函数的返回值进行比较,通常我们会使用 lambda
表达式来指定这个函数。
sorted()
和上面的 max
和 min
函数类似,sorted()
除了按元素本身比较外,还支持通过 key
指定一个函数,按元素总的某项值进行比较。这个函数满足以下要求:
- 参数是序列的一项
- 返回一个可比较类型(如字符串、数字等)
比如同样还是上面的字典列表,我们可以通过 sorted()
函数按照分数进行排序。
data = [ {'name': '张三', 'gender': 'male', 'age': 27, 'score': 88}, {'name': '李四', 'gender': 'female', 'age': 21, 'score': 66}, {'name': '王五', 'gender': 'male', 'age': 24, 'score': 73}, {'name': '赵六', 'gender': 'female', 'age': 20, 'score': 92}, {'name': '孙七', 'gender': 'female', 'age': 22, 'score': 80}, ] # sorted() 支持按用户指定函数(规则),进行排序,还可以指定 reverse=True 进行逆序 print('按分数排序', sorted(data, key=lambda x: x['score']))
sorted()
函数可以对列表进行排序,同样也支持通过 key
参数指定一个函数,按照这个函数的返回值进行排序。
map
函数
map
函数是 Python 中的一个内置函数,它接收两个参数:一个函数和一个可迭代对象,然后将传入的函数依次作用于序列的每个元素,并将结果作为新的迭代器返回。
def square(x): return x * x numbers = [1, 2, 3, 4, 5] # 使用 map 函数将列表中的每个元素求平方 squared_numbers = map(square, numbers) print(list(squared_numbers)) # 输出: [1, 4, 9, 16, 25] # 使用 lambda 表达式定义匿名函数 squared_numbers2 = map(lambda x: x ** 2, numbers) print(list(squared_numbers2))
map()
支持按用户指定函数对数据进行批处理,返回由每一项处理后结果组成的新序列。
filter
函数
filter()
函数支持按用户指定函数过滤数据,这个函数的要求为:
- 参数为序列的一项
- 函数返回
True
时保留该项,否则舍弃该项数据
def is_even(x): return x % 2 == 0 numbers = [1, 2, 3, 4, 5] even_numbers = filter(is_even, numbers) print(list(even_numbers)) # 输出: [2, 4] # 使用 lambda 表达式定义匿名函数 even_numbers2 = filter(lambda x: x % 2 == 0, numbers) print(list(even_numbers2))
filter()
函数返回由过滤后的项组成的迭代器,可以遍历输出或转为列表显示。
reduce
函数
reduce()
函数是把一个函数作用在一个序列 [x1, x2, x3, ...]
上,这个函数必须接收两个参数,`reduce 把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
需要注意 reduce()
函数在 Python 3 中已经被移动到 functools
模块中,需要先导入才能使用。
from functools import reduce def add(x, y): return x + y numbers = [1, 2, 3, 4, 5] sum_numbers = reduce(add, numbers) print(sum_numbers) # 输出: 15 # 使用 lambda 表达式定义匿名函数 sum_numbers2 = reduce(lambda x, y: x + y, numbers) print(sum_numbers2)
在上面代码中我们使用 reduce()
函数计算了列表中所有元素的和,reduce()
函数将序列中的元素依次进行累积运算。
内置的高阶函数可以帮助我们更方便地处理数据,提高代码的可读性和可维护性。