Python 数据类型

190 阅读4分钟

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 的数据类型!