Python 的数据类型系统非常丰富,可以分为可变(Mutable)和不可变(Immutable) 两大类。这种区分对于理解 Python 的内存管理和对象行为至关重要。
下图清晰地展示了Python数据类型的分类及其可变性:
flowchart TD
A[Python数据类型] --> B["不可变(Immutable)"]
A --> C["可变(Mutable)"]
B --> B1[数字类型]
B1 --> B1_1[int<br>整数]
B1 --> B1_2[float<br>浮点数]
B1 --> B1_3[complex<br>复数]
B1 --> B1_4[bool<br>布尔值]
B --> B2[str<br>字符串]
B --> B3[tuple<br>元组]
B --> B4[frozenset<br>不可变集合]
B --> B5[bytes<br>字节序列]
C --> C1[list<br>列表]
C --> C2[dict<br>字典]
C --> C3[set<br>集合]
C --> C4[bytearray<br>可变字节数组]
一、不可变数据类型(Immutable)
不可变类型的对象一旦创建,其值就不能被改变。如果尝试“修改”,实际上是创建了一个新的对象。
1. 数字类型(Numeric Types)
- int(整数):如
42,-10,0 - float(浮点数):如
3.14,-0.001,2.0 - complex(复数):如
1+2j,3-4j - bool(布尔值):是
int的子类,只有两个值:True(1) 和False(0)
2. str(字符串)
- 由 Unicode 字符组成的序列,用单引号
' '、双引号" "或三引号''' '''/""" """定义。 - 例如:
'hello',"世界",'''多行\n字符串'''
3. tuple(元组)
- 有序、不可变的元素集合,用圆括号
()定义。 - 例如:
(1, 2, 3),('a', 'b'),(1, )(注意:单元素元组必须有逗号)
4. bytes(字节串)
- 由字节(0-255)组成的不可变序列,用前缀
b定义。 - 例如:
b'hello',b"\x00\x01"
5. frozenset(不可变集合)
- 与
set类似,但内容不可变。 - 例如:
frozenset([1, 2, 3])
二、可变数据类型(Mutable)
可变类型的对象在创建后,其值可以被修改,而对象的身份(内存地址)保持不变。
1. list(列表)
- 有序、可变的元素集合,用方括号
[]定义。是 Python 中最常用、最灵活的数据结构。 - 例如:
[1, 2, 3],['a', 'b', 'c'],[1, 'hello', 3.14](可以混合类型)
2. dict(字典)
- 无序的键值对(Key-Value)集合,用花括号
{}定义。键必须是不可变类型(如字符串、数字、元组)。 - 例如:
{'name': 'Alice', 'age': 30},{1: 'one', 2: 'two'}
3. set(集合)
- 无序、不重复元素的集合,用花括号
{}或set()函数定义。用于成员测试、去重等。 - 例如:
{1, 2, 3},{'apple', 'banana'}
4. bytearray(可变字节数组)
- 类似于
bytes,但内容可变。 - 例如:
bytearray(b'hello')
三、其他特殊类型
- NoneType:只有一个值
None,表示空值或无值。常用于初始化变量或作为无返回值函数的默认返回值。 - range:表示一个不可变的数字序列,常用于循环。例如:
range(5),range(1, 10, 2) - 自定义类(Class):用户自定义的类型,创建的对象默认是可变(除非特殊设计)。
四、类型检查与转换
1. 类型检查
使用 type() 函数或 isinstance() 函数(更推荐,因为它考虑继承)。
num = 10
print(type(num) is int) # True
print(isinstance(num, int)) # True
# isinstance() 可以检查多个类型
print(isinstance(num, (int, float))) # True
2. 类型转换
Python 提供了内置函数进行显式类型转换。
# 数字与字符串转换
int('123') # 123
float('3.14') # 3.14
str(456) # '456'
# 列表、元组、集合之间的转换
list((1, 2, 3)) # [1, 2, 3] 元组转列表
tuple([1, 2, 3]) # (1, 2, 3) 列表转元组
set([1, 2, 2, 3]) # {1, 2, 3} 列表转集合并去重
list({1, 2, 3}) # [1, 2, 3] 集合转列表
五、可变与不可变的深刻理解(关键区别)
# 不可变示例(str)
str1 = "Hello"
str2 = str1 # str1 和 str2 指向同一个对象
print(id(str1) == id(str2)) # True, 内存地址相同
str1 += " World" # 看似修改,实则是创建了一个新字符串对象
print(id(str1) == id(str2)) # False! 现在内存地址不同了
print(str2) # "Hello" (原对象未被改变)
# 可变示例(list)
list1 = [1, 2, 3]
list2 = list1 # list1 和 list2 指向同一个列表对象
print(id(list1) == id(list2)) # True, 内存地址相同
list1.append(4) # 直接修改了列表对象的内容
print(id(list1) == id(list2)) # True! 内存地址仍然相同
print(list2) # [1, 2, 3, 4] (原对象被改变了)
核心要点:
- 不可变对象在“修改”时会创建新对象,更安全,常用于字典的键。
- 可变对象可以直接修改内容,更高效,但需要小心多个变量引用同一对象时产生的副作用(一个修改,全部受影响)。
希望这个全面的总结能帮助你更好地理解 Python 的数据类型!