Python数据结构深入讲解:列表、字典、元组,彻底搞懂!

🌟 开场白:别让数据结构成为你的拦路虎!

各位Pythoner,大家好!我是你们的老朋友花姐💁‍♀️。

说起Python的数据结构,很多人第一反应是啥?------"这还不简单?" 是的,Python的数据结构确实比C++那种指针乱飞的世界友好太多,但是真正用起来,很多人又容易踩坑,甚至有些高级用法直接被忽略了。

比如,你知道列表(list)在Python底层是如何动态扩容的吗?

你知道字典(dict)的查找为什么那么快?

你知道元组(tuple)真的不可变吗?

今天,咱们就来一场深度解析!


一、列表(List):Python最灵活的数据结构!

1. 列表的基本用法

列表(list)是Python中最常见的数据结构,它支持存储多个元素 ,并且可以包含不同类型的数据。

1.1 创建列表

python 复制代码
# 创建一个普通列表
fruits = ["苹果", "香蕉", "橙子"]

# 创建一个空列表
empty_list = []

# 创建一个包含不同数据类型的列表
mixed_list = [1, "hello", 3.14, True]

1.2 访问和修改列表元素

python 复制代码
fruits = ["苹果", "香蕉", "橙子"]
print(fruits[0])  # 输出: 苹果
print(fruits[-1]) # 输出: 橙子(支持负索引)

fruits[1] = "梨"  # 修改元素
print(fruits)  # 输出: ['苹果', '梨', '橙子']

1.3 添加元素

python 复制代码
fruits.append("葡萄")  # 在列表末尾追加
fruits.insert(1, "西瓜")  # 在指定索引插入元素
print(fruits)

1.4 删除元素

python 复制代码
fruits.remove("橙子")  # 按值删除
del fruits[0]  # 按索引删除
print(fruits)

1.5 遍历列表

python 复制代码
for fruit in fruits:
    print(fruit)

2. 列表的底层原理:动态数组

Python的 list 其实就是动态数组 ,类似C语言的 malloc,它会预留一定的空间,存放数据。如果超出了容量,Python会自动扩容,避免频繁分配内存的性能损耗。

2.1 Python列表是如何扩容的?

python 复制代码
import sys

lst = []
print(f"初始列表大小: {sys.getsizeof(lst)} 字节")

for i in range(10):
    lst.append(i)
    print(f"添加 {i} 后,列表大小: {sys.getsizeof(lst)} 字节")

💡 总结

  • Python的 list 采用动态数组存储元素。
  • 自动扩容 机制提高性能,但如果知道最终大小,可以用 lst = [None] * n 预分配。

二、字典(Dict):Python的查找神器!

1. 字典的基本用法

字典(dict)是一种键值对(key-value)存储的数据结构,类似现实中的"联系人列表"👇:

python 复制代码
# 创建字典
person = {
    "name": "花姐",
    "age": 28,
    "city": "北京"
}

# 访问字典的值
print(person["name"])  # 输出: 花姐

# 添加/修改键值
person["gender"] = "女"
person["age"] = 29
print(person)

# 删除键值
del person["city"]
print(person)

# 遍历字典
for key, value in person.items():
    print(f"{key}: {value}")

2. 字典的查找为什么快?

字典的查询速度比列表快很多 ,因为字典是基于哈希表(Hash Table)实现的。来看下面的对比👇:

python 复制代码
import time

# 用列表查找
lst = list(range(1000000))
start = time.time()
999999 in lst  # 判断是否存在
print(f"列表查找耗时: {time.time() - start:.6f} 秒")

# 用字典查找
dct = {i: None for i in range(1000000)}
start = time.time()
999999 in dct
print(f"字典查找耗时: {time.time() - start:.6f} 秒")

📌 结果 :字典查找远快于列表,因为字典的键存储在哈希表中,查找时直接通过哈希计算位置,而列表需要逐个扫描(O(n))


三、元组(Tuple):真的不可变吗?

1. 元组的基本用法

元组(tuple)和列表很像,但它不可变,一旦创建就无法修改。

python 复制代码
# 创建元组
t = (1, 2, 3)
print(t[0])  # 访问元素

# 不能修改元素(会报错)
# t[0] = 100  #❌ TypeError: 'tuple' object does not support item assignment

# 但可以包含可变对象
t = (1, 2, [3, 4])
t[2].append(5)  # 居然成功了?
print(t)  # (1, 2, [3, 4, 5])

🚀 为什么可变了?

其实,元组本身确实是不可变的 ,但如果元组里存的是可变对象(如列表),那么这个可变对象的内容依然可以被修改

💡 总结

  • 元组的不可变性 指的是元组的结构不可变,但元组内部的可变对象仍然可以改变。
  • 如果要创建真正的不可变数据结构 ,可以使用 collections.namedtupledataclasses.dataclass(frozen=True)

2. Python中的不可变数据结构:namedtupledataclass(frozen=True)

🌟 为什么要用不可变的数据结构?

在 Python 里,默认的数据结构(如 listdict、普通的 tuple)通常是可变的,这意味着我们可以在程序运行时随意更改它们的内容。但在某些场景下,我们希望数据是只读的,比如:

  • 保护数据不被意外修改,防止 bug。
  • 让代码更具有可读性,明确表明某些数据不应更改。
  • 让数据结构可作为字典的 key(可哈希)。

2.1 namedtuple:轻量级的不可变数据结构

Python 的 collections.namedtuple 提供了一种类似 tuple 但带有字段名称 的不可变数据结构。它的底层仍然是 tuple,但可以使用字段名来访问数据,而不是只能用索引,非常方便!

2.1.1 基本使用
python 复制代码
from collections import namedtuple

# 定义一个不可变的 Point 结构体
Point = namedtuple("Point", ["x", "y"])

# 创建 Point 实例
p = Point(3, 5)

print(p.x)  # 3
print(p.y)  # 5
print(p)    # Point(x=3, y=5)

💡 为什么比普通 tuple 好?

python 复制代码
# 使用普通的 tuple
p1 = (3, 5)
print(p1[0])  # 3
print(p1[1])  # 5

# 用索引访问,不直观,容易出错

namedtuple 的最大优势就是可读性更好 !比起 tuple[0]point.x 一眼就能看懂它是什么数据。


2.1.2 namedtuple 是不可变的

既然是不可变数据结构,那么修改字段会报错👇:

python 复制代码
p.x = 10  # ❌ AttributeError: can't set attribute

如果你想要一个类似的结构,但允许修改,可以使用 dataclass(后面会讲)。


2.1.3 namedtuple 的额外功能
2.1.3.1 ._asdict():转换为字典
python 复制代码
p = Point(3, 5)
print(p._asdict())  
# 输出:{'x': 3, 'y': 5}
2.1.3.2 ._replace():创建新实例
python 复制代码
new_p = p._replace(x=10)
print(new_p)  # Point(x=10, y=5)

注意:_replace() 不会修改原来的对象,而是返回一个新的对象。

2.1.3.3 额外默认值
python 复制代码
Person = namedtuple("Person", ["name", "age", "city"])
p = Person._make(["花姐", 28, "北京"])
print(p)  # Person(name='花姐', age=28, city='北京')

2.2 dataclass(frozen=True):更强大的不可变数据结构

namedtuple 已经很不错了,但它还是有一些缺点,比如:

  • 不能设置默认值。
  • 不能使用类型注解。
  • 不能定义方法。

为了解决这些问题,Python 3.7 引入了 dataclasses,其中 frozen=True 可以创建真正不可变的数据结构!


2.2.1 基本使用
python 复制代码
from dataclasses import dataclass

@dataclass(frozen=True)  # 冻结 dataclass,使其不可变
class Point:
    x: int
    y: int

p = Point(3, 5)
print(p.x)  # 3
print(p.y)  # 5

namedtuple 一样,dataclass(frozen=True) 也会阻止修改:

python 复制代码
p.x = 10  # ❌ dataclasses.FrozenInstanceError: cannot assign to field 'x'

⚠️ 注意 :不同于 namedtupledataclass(frozen=True) 底层是 __slots__ + __dict__,而不是 tuple


2.2.2 dataclass(frozen=True) 的优势
✅ 支持默认值
python 复制代码
@dataclass(frozen=True)
class Person:
    name: str
    age: int = 18  # 默认值

p = Person("花姐")
print(p)  # Person(name='花姐', age=18)

相比 namedtupledataclass 可以直接给 age 赋默认值,而 namedtuple 需要用 _replace() 这种不太优雅的方法。


✅ 支持方法

namedtuple 只能存储数据,而 dataclass 还能添加方法👇:

python 复制代码
@dataclass(frozen=True)
class Rectangle:
    width: int
    height: int

    def area(self) -> int:
        return self.width * self.height

r = Rectangle(10, 5)
print(r.area())  # 50

✅ 自动实现 __eq____repr__
python 复制代码
@dataclass(frozen=True)  # 冻结 dataclass,使其不可变
class Point:
    x: int
    y: int
p1 = Point(3, 5)
p2 = Point(3, 5)

print(p1 == p2)  # ✅ True,dataclass 自动实现 __eq__
print(p1)        # ✅ Point(x=3, y=5),自动实现 __repr__

namedtuple 也可以自动实现 __eq__,但 dataclass 允许更多定制,比如:

python 复制代码
@dataclass(frozen=True)
class Point:
    x: int
    y: int

    def __repr__(self):
        return f"坐标({self.x}, {self.y})"

p = Point(3, 5)
print(p)  # 坐标(3, 5)

2.3 namedtuple vs. dataclass(frozen=True):如何选择?

特性 namedtuple dataclass(frozen=True)
不可变
底层结构 tuple __slots__ + __dict__
支持字段默认值
支持类型注解
支持方法
可读性 普通 更优

👉 什么时候用 namedtuple

  • 仅仅是存储少量数据,不需要方法和默认值。
  • 需要快速创建轻量级不可变对象。

👉 什么时候用 dataclass(frozen=True)

  • 需要方法、类型注解、默认值。
  • 需要更好的可读性和可维护性。

🎉 总结:牢记这些关键点!

今天,我们深度解析了Python的三大数据结构:列表、字典、元组 ,并且剖析了它们的底层原理。最重要的几个要点: ✅ 列表(list)可变 、支持动态扩容,适用于存储有序数据。

字典(dict)键值对存储 、查找快,适用于存储映射关系。

元组(tuple)不可变(但内部可变对象仍然可变),适用于存储固定数据。

希望今天的讲解能让你更深入理解Python的数据结构!💪

顺手点赞+在看就是对花姐最大的支持! ❤️🎉

相关推荐
程序员小刚20 分钟前
基于SpringBoot + Vue 的火车票订票系统
vue.js·spring boot·后端
龙虎榜小红牛系统20 分钟前
Python项目源码57:数据格式转换工具1.0(csv+json+excel+sqlite3)
python·json·excel
regret~33 分钟前
【论文笔记】SOTR: Segmenting Objects with Transformers
论文阅读·python·深度学习
CHNMSCS1 小时前
PyTorch_点积运算
人工智能·pytorch·python
拾忆-eleven2 小时前
第三节:OpenCV 基础入门-安装与配置 OpenCV (Python/C++ 环境)
c++·python·opencv
fanTuanye2 小时前
【SpringBoot篇】详解短信验证码登录功能实现
spring boot·后端
DonciSacer2 小时前
第一章-Rust入门
开发语言·后端·rust
西京刀客2 小时前
golang常用库之-标准库text/template
开发语言·后端·golang
[email protected]3 小时前
ASP.NET Core 请求限速的ActionFilter
后端·asp.net·.netcore
CHNMSCS3 小时前
PyTorch_标量张量和数字的转换
人工智能·pytorch·python