Skip to content

内置函数 ​

处理学生数据时,我们经常要完成批量转换、条件筛选、数据配对和排序。如果每次都从头编写循环,代码会比较重复。如何直接复用已有函数,把这些处理步骤连接起来?

Python 已经提供了很多内置函数。本节先解决五类常见问题:

  1. map():批量转换数据
  2. filter():筛选数据
  3. zip():按位置配对数据
  4. sorted():排序数据
  5. eval():计算字符串表达式

还会学习适合编写简单匿名函数的 lambda 表达式。

下面的列表用于速查,不要求背诵。完整接口以 Python 3.14 内置函数文档为准。

  • A:abs()、aiter()、all()、anext()、any()、ascii()
  • B:bin()、bool()、breakpoint()、bytearray()、bytes()
  • C:callable()、chr()、classmethod()、compile()、complex()
  • D:delattr()、dict()、dir()、divmod()
  • E:enumerate()、eval()、exec()
  • F:filter()、float()、format()、frozenset()
  • G:getattr()、globals()
  • H:hasattr()、hash()、help()、hex()
  • I:id()、input()、int()、isinstance()、issubclass()、iter()
  • L:len()、list()、locals()
  • M:map()、max()、memoryview()、min()
  • N:next()
  • O:object()、oct()、open()、ord()
  • P:pow()、print()、property()
  • R:range()、repr()、reversed()、round()
  • S:set()、setattr()、slice()、sorted()、staticmethod()、str()、sum()、super()
  • T:tuple()、type()
  • V:vars()
  • Z:zip()
  • _:__import__()

Python 核心内置函数分类导图

上一节已经知道,函数可以作为参数传给另一个函数。接下来的 map()、filter() 和 sorted() 都会用到这个特点。

map():批量转换 ​

map() 会把指定函数依次应用到每个元素上:

python
map(function, iterable)
  • function:处理单个元素的函数
  • iterable:提供原始数据的可遍历对象

例如,把一组数字统一转换成字符串:

python
numbers = [1, 2, 3, 4, 5]
result = map(str, numbers)

print(result)
print(list(result))

运行结果中的第一行会显示一个 map 对象,第二行才是转换后的列表:

text
<map object at ...>
['1', '2', '3', '4', '5']

Python 3.14 中,map() 返回迭代器,不会直接返回列表。为了查看全部结果,可以使用 list() 转换。

自定义转换:

下面判断 0 到 4 中的每个数是不是奇数:

python
def is_odd(number):
    return number % 2 == 1


result = map(is_odd, range(5))
print(list(result))

运行结果:

text
[False, True, False, True, False]

map() 保留原来的元素数量,只把每个元素转换成函数返回的新结果。

再看一个使用内置函数 abs() 的例子:

python
numbers = [1, -3, 5, 6, -2, 4]
print(list(map(abs, numbers)))

运行结果:

text
[1, 3, 5, 6, 2, 4]

filter():条件筛选 ​

filter() 会保留判断结果为真的元素:

python
filter(function, iterable)

传入的函数负责判断一个元素是否应该保留。

python
def is_odd(number):
    return number % 2 == 1


result = filter(is_odd, range(10))
print(list(result))

运行结果:

text
[1, 3, 5, 7, 9]

filter() 和 map() 一样返回迭代器,因此示例中使用 list() 查看全部结果。

map 与 filter 的迭代器数据流

案例:筛选三位回文数 ​

回文数从左向右读和从右向左读都一样,例如 121、232。

python
def is_palindrome(number):
    text = str(number)
    return text == text[::-1]


result = list(filter(is_palindrome, range(100, 1000)))

print("回文数数量:", len(result))
print("前 10 个:", result[:10])

运行结果:

text
回文数数量: 90
前 10 个: [101, 111, 121, 131, 141, 151, 161, 171, 181, 191]

这里仍然筛选了全部三位回文数,只截取前 10 个展示,避免输出过长。

zip():数据配对 ​

zip() 会按照位置,把多个可遍历对象中的元素配对:

python
names = ["张三", "李四", "王五"]
scores = [88, 92, 85]

result = zip(names, scores)
print(list(result))

运行结果:

text
[('张三', 88), ('李四', 92), ('王五', 85)]

zip() 返回一个迭代器。每次配对得到一个元组,使用 list() 后才会得到由元组组成的列表。

长度不一致:

如果数据长度不同,zip() 默认配对到最短的数据用完为止:

python
names = ["张三", "李四", "王五"]
scores = [88, 92]

print(list(zip(names, scores)))

运行结果:

text
[('张三', 88), ('李四', 92)]

王五 没有对应的成绩,因此不会出现在结果中。

zip 按位置配对并在最短数据处停止

sorted():数据排序 ​

sorted() 会返回一个新的排序列表,不会修改原数据:

python
sorted(iterable, *, key=None, reverse=False)
参数作用
iterable要排序的可遍历对象
key指定从每个元素中取什么值比较
reverse是否倒序,默认为 False

默认顺序与倒序:

python
scores = [75, 92, 88, 60]

print(sorted(scores))
print(sorted(scores, reverse=True))
print(scores)

运行结果:

text
[60, 75, 88, 92]
[92, 88, 75, 60]
[75, 92, 88, 60]

最后一行说明原列表 scores 没有改变。

key 排序规则 ​

学生数据是元组时,默认会先比较第一个元素:

python
students = [("Bob", 75), ("Adam", 92), ("Lisa", 88)]
print(sorted(students))

运行结果:

text
[('Adam', 92), ('Bob', 75), ('Lisa', 88)]

如果要按照成绩排序,可以编写一个函数,让它返回元组中的成绩:

python
def get_score(student):
    return student[1]


students = [("Bob", 75), ("Adam", 92), ("Lisa", 88)]
print(sorted(students, key=get_score))

运行结果:

text
[('Bob', 75), ('Lisa', 88), ('Adam', 92)]

sorted() 会把每个学生元组交给 get_score(),再使用返回的成绩比较大小。

sorted 使用 key 提取比较值

key 还可以接收内置函数。例如,按照字符串长度排序:

python
animals = ["Dog", "Cat", "Rabbit"]
print(sorted(animals, key=len))
print(sorted(animals, key=str.lower))

运行结果:

text
['Dog', 'Cat', 'Rabbit']
['Cat', 'Dog', 'Rabbit']

lambda 表达式 ​

如果一个函数逻辑很短,而且只使用一次,可以使用 lambda 表达式:

python
lambda 参数: 表达式

lambda 会创建函数,但不需要使用 def 编写函数名和函数体。

lambda 表达式语法解构与函数对比

下面两种写法效果相同:

python
def add(number1, number2):
    return number1 + number2


add_lambda = lambda number1, number2: number1 + number2

print(add(12, 34))
print(add_lambda(12, 34))

运行结果:

text
46
46

lambda 的冒号后面只能写一个表达式,这个表达式的结果就是返回值。

filter() 中的 lambda:

python
numbers = range(10)
result = filter(lambda number: number % 2 == 1, numbers)

print(list(result))

运行结果:

text
[1, 3, 5, 7, 9]

筛选非空字符串也可以使用 lambda:

python
texts = ["A", "", "B", None, "C", ""]
result = filter(lambda text: text and text.strip(), texts)

print(list(result))

运行结果:

text
['A', 'B', 'C']

sorted() 中的 lambda:

前面的成绩排序函数只有一行,可以改成 lambda:

python
students = [("Bob", 75), ("Adam", 92), ("Lisa", 88)]
result = sorted(students, key=lambda student: student[1])

print(result)

运行结果:

text
[('Bob', 75), ('Lisa', 88), ('Adam', 92)]

如果函数逻辑较长、需要重复使用,仍然优先使用 def 定义具名函数。

案例:成绩排行榜 ​

需求:把学生姓名和成绩处理成按成绩倒序排列的排行榜,只保留及格学生,并生成可直接输出的文本。

功能分析:依次使用 zip() 配对、filter() 筛选、sorted() 排序和 map() 转换。

具体步骤:

  1. 把学生姓名和成绩配对
  2. 只保留不低于 60 分的学生
  3. 按照成绩从高到低排序
  4. 生成方便输出的文本
python
names = ["张三", "李四", "王五", "赵六"]
scores = [88, 52, 95, 76]

students = zip(names, scores)
passed_students = filter(lambda student: student[1] >= 60, students)
ranked_students = sorted(
    passed_students,
    key=lambda student: student[1],
    reverse=True,
)
ranking = map(
    lambda student: f"{student[0]}:{student[1]} 分",
    ranked_students,
)

print(list(ranking))

运行结果:

text
['王五:95 分', '张三:88 分', '赵六:76 分']

成绩排行榜的四步数据流

这段代码按照数据流逐步处理:配对、筛选、排序、转换。每一步的结果都会交给下一步。

列表推导式还是函数工具

简单转换和筛选使用列表推导式通常更直观。map()、filter() 的优势是可以直接接收已有函数,并且能够把多个处理步骤连接起来。根据代码是否容易阅读来选择,不必强行使用某一种写法。

eval() 与安全边界 ​

当表达式保存在字符串中时,可以使用 eval() 将它当成 Python 表达式计算并返回结果:

python
eval(source, globals=None, locals=None)
  • source:要计算的字符串或已编译代码对象
  • globals:计算时使用的全局命名空间
  • locals:计算时使用的局部命名空间

初学阶段先看最基本的用法:

python
x = 2
expression = "x ** 2 + 2 * x + 1"

result = eval(expression)
print(result)

运行结果:

text
9

不要计算不可信字符串

eval() 会执行字符串中的 Python 表达式。如果内容来自用户输入、网络请求或其他不可信来源,可能执行危险代码。真实项目中不要直接把这些内容交给 eval()。

eval 的安全边界

小结 ​

本节围绕五个问题掌握内置函数:

  1. 如何批量转换或筛选数据?使用 map() 和 filter()。
  2. 如何按位置配对数据?使用 zip(),长度不同时以最短数据为准。
  3. 如何排序且不修改原数据?使用 sorted(),并通过 key 指定排序依据。
  4. 如何编写只使用一次的短函数?使用 lambda 表达式。
  5. 如何计算字符串表达式?使用 eval(),但不能处理不可信内容。

练习 ​

  1. 使用 map() 把数字列表中的所有元素转换成字符串
  2. 使用 filter() 筛选 1 到 20 之间的偶数
  3. 使用 zip() 把姓名列表和成绩列表配对
  4. 使用 sorted() 和 lambda 按照元组的第二个元素倒序排列
  5. 修改成绩排行榜,只保留不低于 80 分的学生