Skip to content

内置函数、解包相关操作

更新: 2025/2/24 字数: 0 字 时长: 0 分钟

本节我们会学习一些常用的内置函数和解包相关操作,为后面紧接着的函数学习打好基础。

内置函数

内置函数,也就是 Python 解释器自带的函数,也是 Python 语言的核心组成部分。当 Python 解释器启动以后,所有的内置函数也就生效了,无需导入任何模块,可以直接拿来使用。例如 input 输入函数、print 输出函数、len 长度函数等,这些函数都是 Python 的内置函数。除此之外,在 Python 中还有很多内置函数,这里再列举一些。

帮助提示

help(内置函数或内置数据类型) 返回其源代码里面的注释内容。

python
print(help(str))  # 输出:class str(object)...。注释:返回了Python中str类型源代码里面的注释内容。

dir(内置函数或内置数据类型) 返回内置函数或内置数据类型自带的可执行操作。

python
print(dir(str))  # 输出:['__add__',..., 'capitalize', 'casefold', 'center', 'count'...]。注释:返回了Python中str类型自带的可执行操作。

数学计算

abs(值) 返回整型、浮点型数值的绝对值。

python
print(abs(-10))    # 输出:10
print(abs(-12.1))  # 输出:12.1

round(值, ndigits=0) 返回浮点型数值四舍五入后的数值。

python
print(round(0.655))             # 输出:1。注释:默认不保留小数。
print(round(0.655, ndigits=1))  # 输出:0.7。注释:ndigits=1,保留1位小数。
print(round(0.655, ndigits=2))  # 输出:0.66。注释:ndigits=2,保留2位小数。

divmod(除数, 被除数) 返回除法运算后的商数和余数。

python
print(divmod(10, 3))  # 输出:(3, 1)。注释:3为商,1为余数。

pow(底数, 幂数) 返回底数经过幂数次方后的结果。

python
print(pow(10, 3))  # 输出:1000。注释:返回10的3次方。

逻辑运算

all() 用于判断可迭代对象中的元素是否全部为 True。如果所有元素都为 True,则返回 True,否则返回 False

python
print(all([1 < 5]))                # 输出:True
print(all([1 < 5, 3 > 2]))         # 输出:True
print(all([1 < 5, 3 > 2, 5 > 7]))  # 输出:Flase

any(可迭代对象) 用于判断可迭代对象中的元素是否有一个为 True。如果有一个元素为 True,则返回 True,否则返回 False

python
print(any([1 < 5]))                # 输出:True
print(any([1 < 5, 3 > 2]))         # 输出:True
print(any([1 < 5, 3 > 2, 5 > 7]))  # 输出:True

枚举函数

enumerate(可迭代对象) 将可迭代对象中的每个元素与其对应的索引值(从 0 开始)配对,最后返回一个 enumerate 对象。

python
fruits = ['apple', 'banana', 'cherry']
print(type(enumerate(fruits)))  # 输出:<class 'enumerate'>

enumerate 对象是可迭代对象,因此可以在 for 循环中遍历它,每次循环得到的结果就是一个包含索引和对应元素所组成的元组

python
fruits = ['apple', 'banana', 'cherry']
# 使用for循环遍历enumerate对象
for item in enumerate(fruits):
    print(item)
'''
输出:
(0, 'apple')
(1, 'banana')
(2, 'cherry')
'''

不仅如此,enumerate 对象还可以传递给 list()tuple() 等将其转为其他序列类型,不过最常用的还是在循环中同时获取元素和索引

python
fruits = ['apple', 'banana', 'cherry']
# for循环同时获取元素和索引
for index, fruit in enumerate(fruits):
    print(index, fruit)
'''
输出:
0 apple
1 banana
2 cherry
'''

重要

强烈建议在需要对可迭代对象中的元素和它的位置一起进行操作时使用 enumerate(可迭代对象) 函数。如果你不使用 enumerate,就需要引入 range(len(可迭代对象)) 来手动管理元素索引,这不仅代码变得更复杂,而且增加了出错的可能性,比如索引超出范围、管理不当等问题。总之,使用 enumerate 可以减少这些人为错误,让代码更加简洁易读。

迭代排序

sorted(iterable, key=None, reverse=False) 对可迭代对象中的元素进行排序,返回一个新的排好序的列表对象。

  • iterable -- 可迭代对象。
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序方式,False 升序(默认),True 降序 。
python
print(sorted('213bac'))                        # 输出:['1', '2', '3', 'a', 'b', 'c']。注释:升序排序可迭代对象'213bac'中的元素。
print(sorted('213bac', reverse=True))          # 输出:['c', 'b', 'a', '3', '2', '1']。注释:降序排序可迭代对象'213bac'中的元素。
print(sorted(range(5)))                        # 输出:[0, 1, 2, 3, 4]。注释:升序排序可迭代对象range(5)中的元素。
print(sorted(range(5), reverse=True))          # 输出:[4, 3, 2, 1, 0]。注释:降序排序可迭代对象range(5)中的元素。
print(sorted([1, 2, 4, 3, 0]))                 # 输出:[0, 1, 2, 3, 4]。注释:可迭代对象升序输出。
print(sorted([1, 2, 4, 3, 0], reverse=True))   # 输出:[4, 3, 2, 1, 0]。注释:可迭代对象降序输出。
print(sorted('20143', key=int))                # 输出:['0', '1', '2', '3', '4']。注释:将字符串中每个字符转换为int类型进行升序排序,但结果仍是字符型。
print(sorted('20143', key=int, reverse=True))  # 输出:['4', '3', '2', '1', '0']。注释:将字符串中每个字符转换为int类型进行降序排序,但结果仍是字符型。

a = {'z': 2, 'x': 3, 'y': 1}
print(sorted(a))                                            # 输出:['x', 'y', 'z']。注释:遍历字典中的键升序输出。
print(sorted(a, reverse=True))                              # 输出:['z', 'y', 'x']。注释:遍历字典中的键降序输出。
print(sorted(a, key=a.get))                                 # 输出:['y', 'z', 'x']。注释:遍历字典中的值升序输出键。
print(sorted(a, key=a.get, reverse=True))                   # 输出:['x', 'z', 'y']。注释:遍历字典中的值降序输出键。
print(sorted(a.items()))                                    # 输出:[('x', 3), ('y', 1), ('z', 2)]。注释:遍历字典视图的第一个元素升序输出。
print(sorted(a.items(), reverse=True))                      # 输出:[('z', 2), ('y', 1), ('x', 3)]。注释:遍历字典视图的第一个元素降序输出。
print(sorted(a.items(), key=lambda d: d[0]))                # 输出:[('x', 3), ('y', 1), ('z', 2)]。注释:遍历字典视图的第一个元素升序输出。
print(sorted(a.items(), key=lambda d: d[0], reverse=True))  # 输出:[('z', 2), ('y', 1), ('x', 3)]。注释:遍历字典视图的第一个元素降序输出。
print(sorted(a.items(), key=lambda d: d[1]))                # 输出:[('y', 1), ('z', 2), ('x', 3)]。注释:遍历字典视图的第二个元素升序输出。
print(sorted(a.items(), key=lambda d: d[1], reverse=True))  # 输出:[('x', 3), ('z', 2), ('y', 1)]。注释:遍历字典视图的第二个元素降序输出。

组合打包

zip(可迭代对象1, 可迭代对象2...) 把每个可迭代对象中下标相同的元素组合在一起,返回一个可迭代的 zip 对象,可以使用 list() 函数转换为列表,也可以使用 dict() 函数转换为字典,还可以使用 max/min 获取最大/最小值。

python
a = [1, 2, 3]
b = zip(a)
print(b, list(b))  # 输出:zip对象,[(1,), (2,), (3,)]。注释:把可迭代对象中每个元素单独分开。
c = [4, 5, 6]
d = zip(a, c)
print(d, list(d))  # 输出:zip对象,[(1, 4), (2, 5), (3, 6)]。注释:把每个可迭代对象中下标相同的元素组合在一起。
e = [7, 8]
f = zip(a, c, e)
print(f, list(f))  # 输出:zip对象,[(1, 4, 7), (2, 5, 8)]。注释:可迭代对象长度不一致时,以最短的长度进行组合。

a = {'z': 2, 'x': 3, 'y': 1}
print(list(zip(a.keys(), a.values())))  # 输出:[('z', 2), ('x', 3), ('y', 1)]
print(list(zip(a.values(), a.keys())))  # 输出:[(2, 'z'), (3, 'x'), (1, 'y')]
print(dict(zip(a.keys(), a.values())))  # 输出:{'z': 2, 'x': 3, 'y': 1}。注释:键值不交换位置。
print(dict(zip(a.values(), a.keys())))  # 输出:{2: 'z', 3: 'x', 1: 'y'}。注释:键值交换位置,前提是值必须可哈希。
print(max(zip(a.keys(), a.values())))   # 输出:('z', 2)。注释:获取字典中最大的键和所对应的值。
print(max(zip(a.values(), a.keys())))   # 输出:(3, 'x')。注释:获取字典中最大的值和所对应的键。
print(min(zip(a.keys(), a.values())))   # 输出:('x', 3)。注释:获取字典中最小的键和所对应的值。
print(min(zip(a.values(), a.keys())))   # 输出:(1, 'y')。注释:获取字典中最小的值和所对应的键。

提醒

内置函数的数量是被严格控制的,否则 Python 解释器会变得庞大和臃肿。一般来说,只有那些使用频繁或者和语言本身绑定比较紧密的函数,才会被提升为内置函数。例如,在屏幕上输出文本就是使用最频繁的功能之一,在 Python 2.x 中,print 是一个关键字;到了 Python 3.x 中,print 变成了内置函数。

解包相关操作

在 Python 中,* 符号是一种非常灵活的工具,它不仅可以用来进行乘法运算,还可以用来重复输出字符串、列表等。不仅仅如此,* 符号还可用作解包运算符,也就是将可迭代对象(如列表、元组等)展开,将里面的元素作为独立的值使用。另外在 Python 中,** 符号也是一种非常灵活的工具,它不仅可以用来进行幂运算,也可以用做解包运算符,不过是针对于字典的解包符

解包合并

直接说概念的话,有人可能不太容理解,具体看下面的例子:

  • 问题一:比如有一个列表,我们希望每隔一个空格挨个输出列表里面的元素,该怎么写呢?
  • 问题二:比如我们希望利用 range 函数,每隔一个空格挨个输出 0 ~ 10 的所有偶数,该怎么写呢?
  • 问题三:比如有一个列表,有一个元组,我们希望将两个对象中的所有元素放到一个集合中,该怎么写呢?
  • 问题四:比如有两个变量分别对应字典,我们希望创建第三个变量来存储融合后的两个字典,该怎么写呢?有的人可能会按下面的方式来写:
python
num_list = [1, 2, 3, 4, 5]

# 写法一:循环不换行输出
for num in num_list:
    print(num, end=' ')  # 输出:1 2 3 4 5

# 写法二:推导式结合str方法、join方法
print(' '.join([str(num) for num in num_list]))  # 输出:1 2 3 4 5
python
range_obj = range(0, 10, 2)

# 写法一:循环不换行输出
for num in range_obj:
    print(num, end=' ')  # 输出:0 2 4 6 8

# 写法二:推导式结合str方法、join方法
print(' '.join([str(num) for num in range_obj]))  # 输出:0 2 4 6 8
python
num_list = [1, 2, 3, 4]
num_tuple = (4, 5, 6, 7)

# 写法一:新建集合循环添加
num_set = set()
for num in num_list:
    num_set.add(num)
for num in num_tuple:
    num_set.add(num)
print(num_set)  # 输出:{1, 2, 3, 4, 5, 6, 7}

# 写法二:类型转换求并集
num_set = set(num_list) | set(num_tuple)
print(num_set)  # 输出:{1, 2, 3, 4, 5, 6, 7}
python
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
dict3 = dict1.copy()  # 注释:复制除一个新的字典对象。
dict3.update(dict2)
print(dict3)          # 输出:{'a': 1, 'b': 2, 'c': 3, 'd': 4}

以上三个问题,虽然能用前面所学的知识解决,但使用解包运算符将会更加便捷

  • 答案一:使用 * 将可迭代对象(如列表、元组等)解包展开。
  • 答案二:使用 *range 对象(也是可迭代对象)解包展开。
  • 答案三:使用 * 将可迭代对象(如列表、元组等)解包展开,通过 {*列表, **元组} 来合并两个或多个列表或字典,返回一个新的集合。
  • 答案四:使用 ** 将字典解包展开,通过 {**字典1, **字典2} 来合并两个或多个字典,返回一个新的字典,但要注意后面的字典会覆盖前面的字典中相同键的键值。
python
num_list = [1, 2, 3, 4, 5]
print(*num_list)  # 输出:1 2 3 4 5
python
range_obj = range(0, 10, 2)
print(*range_obj)  # 输出:0 2 4 6 8
python
num_list = [1, 2, 3, 4]
num_tuple = (4, 5, 6, 7)
num_set = {*num_list, *num_tuple}
print(num_set)  # 输出:{1, 2, 3, 4, 5, 6, 7}
python
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
dict3 = {**dict1, **dict2}
print(dict3)  # 输出:{'a': 1, 'b': 2, 'c': 3, 'd': 4}

建议

解包符不仅写法简洁,而且功能强大,尤其在处理列表、字典、元组等数据时极为方便。

解包赋值

看了上面的的一些解包案例,相信有人已经能感觉到解包运算符的灵活性了,这里我们再看下面解包赋值的案例。回顾前面我们讲变量赋值的时候,讲过如下两种变量赋值格式:

  • 单个变量赋值格式:变量 = 对象
  • 多个变量赋值格式:变量1, 变量2... = 对象1, 对象2...

当时就提到,赋值多个变量时,变量和对象的个数要一致,否则就会报错。那么假如多个对象赋值一个变量,结果是什么类型呢?具体看下面的代码:当多个对象赋值给一个变量时,它会被自动打包成元组

python
num = 5, 10            # 注释:等价于num = (5, 10)
print(num, type(num))  # 输出:(5, 10) <class 'tuple'>

现在变量 num 是一个包含两个元素的元组,如果我们将 num 赋值给两个变量会发生什么呢?具体看下面的代码:将含有两个元素的元组 num 赋值给两个变量时,元组会被自动解包,将元组中的每个元素会被逐一赋值给 = 号左边的变量

python
a, b = num   # 注释:等价于a, b = (5, 10)
print(a, b)  # 输出:5 10

这个自动解包机制不仅限于元组,也适用于其他可迭代对象,比如列表:

python
x, y, z = [1, 2, 3]
print(x, y, z)  # 输出:1 2 3

但如果变量的数量与可迭代对象中的元素数量不匹配,自动解包就会出现异常

python
# 元素数量比变量少
a, b, c = (1, 2)  # ValueError: not enough values to unpack

# 元素数量比变量多
a, b = (1, 2, 3)  # ValueError: too many values to unpack

这时就可以使用 *变量 的写法,让变量以列表的形式接收零个或多个元素

python
*a, b = [1]
print(a, b)  # 输出:[] 1

a, *b = [1]
print(a, b)  # 输出:1 []

*a, b = [1, 2]
print(a, b)  # 输出:[1] 2

a, *b = [1, 2]
print(a, b)  # 输出:1 [2]

*a, b = [1, 2, 3]
print(a, b)  # 输出:[1, 2] 3

a, *b = [1, 2, 3]
print(a, b)  # 输出:1 [2, 3]

*a, b, c = [1, 2, 3, 4]
print(a, b, c)  # 输出:[1, 2] 3 4

a, *b, c = [1, 2, 3, 4]
print(a, b, c)  # 输出:1 [2, 3] 4

a, b, *c = [1, 2, 3, 4]
print(a, b, c)  # 输出:1, 2 [3, 4]

重要

解包符 * 能够处理多个变量的同时赋值,也就是可以用于分配可迭代对象中的元素,非常适合在不确定数量的元素时使用。但需要注意,同时赋值的多个变量中,只允许一个变量带有 * 符号。

解包传参

在一些内置函数的源码中,我们经常能看到 *args 这样写法,它用于将所有传递给函数的零个或多个元素以元组的形式打包起来,并将其赋值给变量 args。以内置的 print 输出函数为例:

image-20240930153217560

print 输出函数的源码中使用了 *args 来处理多个元素的输入,因此我们可以传递多个值给 print 函数,它会依次输出这些值,并在它们之间插入一个空格

python
print(1, 2, 3, 4, 5)  # 输出:1 2 3 4 5

结合上面解包的内容,我们还可以这样来写:

python
numbers = [1, 2, 3, 4, 5]
print(*numbers)  # 输出:1 2 3 4 5。注释:解包符*将number解包为多个元素传递给print函数。

另外,在 print 输出函数的源码中,我们能看到 sepend 参数,在前面也学习过这两个参数的作用,一个是元素间间隔的填充内容,一个是输出结尾的填充内容,使用方式如下:

python
numbers = [1, 2, 3, 4, 5]
print(*numbers, sep='*', end='s')  # 输出:1*2*3*4*5s

上面函数中通过 参数='值' 这种方式传递参数称之为“关键字参数”,在这里我们可以将 参数 作为键, 作为值,保存在一个字典中,通过 ** 解包字典中的键值对为关键字参数传递给函数。于是上面的函数案例我们可以这样来写:

python
numbers = [1, 2, 3, 4, 5]
argument = {'sep': '*', 'end': 's'}
print(*numbers, **argument)  # 输出:1*2*3*4*5s

提醒

关于函数的“关键字参数”,在后面的函数学习中会有详细介绍。