Skip to main content

Python 数据类型

常用数据类型的公共方法

我们已经学习完了 Python 内置数据类型的字符串、列表、元组、字典和集合。本节我们将总结一下这些数据类型所共有的方法,主要从两个方面介绍,即运算符和内置函数。

  • 运算符

首先,让我们来看一下运算符。在运算符方面,主要有四个,即加法运算符、乘法运算符、in 关键字和 not in 关键字。如下图所示:

01运算符汇总

加法运算符用于将两个数据合并成一个新的数据,支持的数据类型有字符串、列表和元组。

列表"+"运算符应用实例:

#列表"+"运算符
list1 = [1,2,3]
list2 = [4,5,6]
list_val = list1 + list2
print(list_val)

输出结果:

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

元组"+"运算符应用实例:

#元组"+"运算符
tuple1 = (1,2,3)
tuple2 = (4,5,6)
tuple_val = tuple1 + tuple2
print(tuple_val)

输出结果:

(1, 2, 3, 4, 5, 6)

字典"+"运算符应用实例:

#字典"+"运算符
dict1 = {'name':'Andy'}
dict2 = {'name':'Jack'}
dict_val = dict1 + dict2
print(dict_val)

输出结果:

TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

结果这里提示我们错误了,因为加法运算符它不支持字典操作,同样的它也不支持集合。

乘法运算符除了可以实现乘法运算外,还可以用于复制数据,同样支持的数据类型也包括字符串、列表和元组,不支持字典和集合。

乘法运算符应用实例:

print ('-'*10)
list_val = [1,2,3]
tuple_val = (1,2,3)
print (list_val*10)
print (tuple_val*10)

输出结果:

----------
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
(1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3)

而 in 和 not in 则是用来判断元素是否存在于集合中的关键字,返回的结果是布尔类型 True 或 False。

列表应用实例:

# in or not in
val = 'hello'
if val in ['hello',123'world']:
print('该元素存在')
else:
print('该元素不存在')

输出结果:

该元素存在

元组应用实例:

# in or not in
val = 'hello'
if val in ('hello',123):
print('该元素存在')
else:
print('该元素不存在')

输出结果:

该元素存在

字典应用实例:

# in or not in,注意判断字典应该判断的是键名
val = 'hello'
if val in {'hello':123}:
print('该元素存在')
else:
print('该元素不存在')

输出结果:

该元素存在
  • 数据类型通用的函数

接下来,我们来看每种数据类型通用的函数。首先是 len 函数,用于计算容器中元素的个数,比如字符串、列表、元组等。然后是 max 和 min 函数,分别用于获取容器中的最大值和最小值。最后是 del 函数,用于删除变量。需要注意的是,在删除字典类型数据时,如果要删除字典中的某个元素,需要根据键名来删除;如果要删除整个字典,直接使用 del 字典名称即可。如下图所示:

02通用函数汇总

len函数应用实例:

# len()字符串应用
val = 'hello'
print(len(val))

# len()元组应用
val1 = ('hello',)
val2 = ('hello','world',('1','2','3'))
print(len(val1))
print(len(val2))

# len()列表应用
val3 = ['hello']
val4 = ['hello','world',('1','2','3')]
print(len(val1))
print(len(val2))

# len()字典应用
val5 = {'name':'andy','age':18,'gender':'male','hoby':['basketball','football']}
print(len(val5))

输出结果:

5
1
3
1
3
4

max函数应用实例:

# max()列表应用
val1 = [1,3,4,5,1,34]
val2 = [1,3,4,5,1,34,'a','b']
val3 = ['a','b']
print (max(val1))
print (max(val2))
print (max(val3))

# max()字典应用
val4 = {'name':'andy','age':18,'gender':'male','hoby':['basketball','football']}
print(max(val4))

输出结果:

34
TypeError: '>' not supported between instances of 'str' and 'int'
b
name

del函数应用实例:

# del()字典应用
val1 = {'name':'andy','age':18,'gender':'male'}
del(val1['name'])
print(val1)

输出结果;

{'age': 18, 'gender': 'male'}

以上是常用数据类型的公共方法,包括运算符和内置函数的使用。

数据类型可变与不可变

本节我们将介绍数据类型的可变性与不可变性。在这里,我们对各种数据类型进行了分类,将其分为不可变类型和可变类型。如下图所示:

03可变类型和不可变类型

对于不可变类型,包括number数值类型、string字符串类型和tuple元组类型。而可变类型则有list列表类型、dict字典类型和set集合类型。需要注意的是集合类型,虽然它是可变类型,但你不能够更改集合中不可变的元素。例如,在一个集合中,若包含元组、列表和字典,你可以改变集合中列表和字典的元素,但不能改变元组的元素,因为元组是不可变的。这是集合类型的特点。

我们一直在强调数据类型的可变和不可变,那么可变和不可变又有什么用呢?当你了解了这些数据类型、它们的可变和不可变性后,你就能够避免在开发过程中遇到一些难以发现、难以排查的问题。接下来我们将在代码中演示这一点。我们新建一个Python文件,命名为mutable_vs_immutable。

  • 不可变类型

首先我们来看一下不可变类型,对于不可变类型,它是不可以被更改的。比如说,我们有一个元组,命名为tuple_val。由于我们不能更改这个元组中的元素,所以当我们要更改一个元组的时候,我们就需要创建一个新的变量,开辟一个新的内存。

# 不可变类型
tuple_val = (1,2,3)
new_tuple = tuple_val + (4,5,6)
print(new_tuple)
print(tuple_val)

输出结果:

(1, 2, 3, 4, 5, 6)
(1, 2, 3)

那如果我只取输出结果的23,然后和456进行拼接,这个时候你就可以使用切片了。这样的操作不会改变原来的tuple_val,它仍然是123。这就是不可变类型的特点。

# 不可变类型
tuple_val = (1,2,3)
new_tuple = tuple_val[1:3] + (4,5,6)
print(new_tuple)
print(tuple_val)

输出结果:

(2, 3, 4, 5, 6)
(1, 2, 3)
  • 可变类型

接下来我们来看可变类型。可变类型经常容易出现错误。首先我们来看第一个问题:赋值问题,我们以一个字典为例,命名为dict_val,有一个键名为name,值为Andy。现在我们将这个字典赋值给一个变量,命名为new_dict。接下来我们对dict_val进行修改,给它添加一个元素。代码如下:

# 赋值常见问题
dict_val = {'name':'andy'}
new_dict = dict_val
dict_val['age'] = 18
print(dict_val)
print(new_dict)

输出结果:

{'name': 'andy', 'age': 18}
{'name': 'andy', 'age': 18}

结果会发现new_dict也随之更改了。这是为什么呢?前面我们在介绍列表的时候,已经介绍过这种情况,就是说这里的new_dict和dict_val它们指向的是同一个内存地址。当你修改了这个dict_val的时候,new_dict也随之改变了。对于这种情况,我们可以通过可视化方式来更好地理解。还记得我们之前推荐的一个网站吗?在浏览器地址栏输入pythontutor.com。然后将程序复制到网站上进行演示。通过可视化,我们可以清晰地看到变量的指向和修改过程。这就是可变类型赋值需要注意的地方。如下图所示:

04python可视化

如果你不想要这种改变,你可以创建一个副本,使用.copy()方法来创建一个副本,这样它就不会发生变化了。代码如下:

# 可变类型
# 复制
dict_val = {'name':'andy'}
new_dict = dict_val.copy()
dict_val['age'] = 18
print(dict_val)
print(new_dict)

输出结果:

{'name': 'andy', 'age': 18}
{'name': 'andy'}

接下来我们再来看一个由不可变类型经常引发的错误。我们定义一个列表,命名为data,其中包含元素11、22和33。现在我们循环遍历这个data,使用for循环。在遍历的过程中,我们判断一下,如果这里的元素等于33或者44,那么我们就给它移除,删除掉。代码如下:

# 循环过程中可变类型元素引发的bug
data = [11,22,33,44,55,66,77]
for i in data:
if i == 33 or i == 44:
data.remove(i)
print(data)

输出结果:

[11, 22, 44, 55, 66, 77]

在正常情况下,这个data应该输出11、22、55、66、77。我们运行代码后,可以观察到输出结果,你能否快速发现问题所在呢?为了更好地理解这个问题,我们将使用可视化方式来运行这段代码。首先,我们复制并编辑了代码。然后,我们按步骤运行代码。

05代码可视化

原来的33已经被移除了,而现在的列表呢,就变成11 22 44 55 66 77,对于33的位置,原来它的索引是2,它被删除以后,后面的整体向前移动了一位。为了解决这个bug,我们创建了一个临时列表temp,当i等于33或44时,我们将这两个值写入temp中,而不是直接删除。现在我们输出temp,结果是33、44。接着,我们再从data中删除33和44,使用for循环遍历temp列表,并删除data中的相应元素。最终,输出data,得到了11、22、55、66、77的结果。代码如下:

# 循环过程中删除可变类型元素引发的bug
data = [11,22,33,44,55,66,77]
list_temp = []
for i in data:
if i == 33 or i == 44:
list_temp.append(i)
print(list_temp)

for i in list_temp:
if i == 33 or i == 44:
data.remove(i) # [11,22,55,66,77]
print(data)

输出结果:

[33, 44]
[11, 22, 55, 66, 77]

这种做法之所以有效,是因为在for循环遍历时,我们操作的是temp列表,而删除操作则是针对data列表进行的。这样一来,当第一次满足条件时,data.remove操作删除了33,第二次满足条件时,又删除了44,最终得到了正确的结果。另外,当我们学习函数参数时,也会遇到可变类型引发的bug。相关内容将在函数章节进行介绍。