[Python教程系列-03] 数据结构详解:掌握Python内置数据结构的使用

68 阅读13分钟

引言

在前面两章中,我们学习了Python的基础语法、控制结构和函数。这些知识为我们编写程序打下了坚实的基础。然而,在实际编程中,我们经常需要处理大量的数据,这就需要使用合适的数据结构来组织和管理这些数据。

Python提供了多种内置的数据结构,每种都有其独特的特点和适用场景。正确选择和使用数据结构不仅能提高程序的效率,还能让代码更加清晰易懂。

在本章中,我们将深入学习Python中最常用的四种内置数据结构:列表(List)、元组(Tuple)、字典(Dictionary)和集合(Set)。我们将探讨它们的特点、使用方法以及在实际编程中的应用场景。

学习目标

完成本章学习后,你将能够:

  1. 理解并熟练使用列表(List)进行数据存储和操作
  2. 掌握元组(Tuple)的特点及其与列表的区别
  3. 熟练使用字典(Dictionary)进行键值对数据的管理
  4. 理解集合(Set)的特点及其在去重和集合运算中的应用
  5. 根据不同场景选择合适的数据结构
  6. 掌握各种数据结构的常用方法和操作
  7. 编写高效的数据处理程序

核心知识点讲解

列表(List)

列表是Python中最常用的数据结构之一,它是一个有序的可变集合,可以存储不同类型的数据。

创建列表

# 创建空列表
empty_list = []

# 创建包含元素的列表
numbers = [1, 2, 3, 4, 5]
fruits = ["苹果", "香蕉", "橙子"]
mixed = [1, "hello", 3.14, True]

# 使用list()函数创建列表
chars = list("Python")  # ['P', 'y', 't', 'h', 'o', 'n']

访问列表元素

fruits = ["苹果", "香蕉", "橙子", "葡萄"]

# 通过索引访问元素(从0开始)
print(fruits[0])    # 输出: 苹果
print(fruits[2])    # 输出: 橙子

# 负索引(从-1开始,表示倒数第一个元素)
print(fruits[-1])   # 输出: 葡萄
print(fruits[-2])   # 输出: 橙子

# 切片操作
print(fruits[1:3])  # 输出: ['香蕉', '橙子']
print(fruits[:2])   # 输出: ['苹果', '香蕉']
print(fruits[2:])   # 输出: ['橙子', '葡萄']

修改列表

fruits = ["苹果", "香蕉", "橙子"]

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

# 修改多个元素
fruits[1:3] = ["葡萄", "柠檬"]
print(fruits)  # 输出: ['苹果', '葡萄', '柠檬']

列表常用方法

fruits = ["苹果", "香蕉", "橙子"]

# 添加元素
fruits.append("葡萄")        # 在末尾添加元素
fruits.insert(1, "草莓")     # 在指定位置插入元素
fruits.extend(["柠檬", "西瓜"])  # 添加多个元素

# 删除元素
fruits.remove("香蕉")        # 删除指定元素
removed_fruit = fruits.pop() # 删除并返回最后一个元素
removed_fruit = fruits.pop(0) # 删除并返回指定位置的元素
fruits.clear()               # 清空列表

# 查找元素
fruits = ["苹果", "香蕉", "橙子", "苹果"]
print(fruits.index("香蕉"))    # 输出: 1
print(fruits.count("苹果"))    # 输出: 2

# 排序
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort()               # 升序排序
numbers.sort(reverse=True)   # 降序排序

# 反转
numbers.reverse()

# 复制列表
original = [1, 2, 3]
copy1 = original.copy()      # 浅拷贝
copy2 = original[:]          # 切片复制
copy3 = list(original)       # 使用list()函数

列表推导式

列表推导式是一种简洁创建列表的方法:

# 基本用法
squares = [x**2 for x in range(10)]
print(squares)  # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 带条件的列表推导式
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)  # 输出: [0, 4, 16, 36, 64]

# 嵌套列表推导式
matrix = [[i*j for j in range(1, 4)] for i in range(1, 4)]
print(matrix)  # 输出: [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

元组(Tuple)

元组与列表类似,但它是不可变的(immutable),一旦创建就不能修改。

创建元组

# 创建空元组
empty_tuple = ()

# 创建包含元素的元组
point = (3, 4)
person = ("张三", 25, "北京")

# 单元素元组需要加逗号
single = (42,)  # 注意逗号

# 不使用括号也可以创建元组
coordinates = 1, 2, 3

访问元组元素

person = ("张三", 25, "北京")

# 通过索引访问元素
print(person[0])   # 输出: 张三
print(person[-1])  # 输出: 北京

# 切片操作
print(person[1:])  # 输出: (25, '北京')

元组的特点

# 元组不可变
point = (3, 4)
# point[0] = 5  # 这会报错: TypeError

# 元组可以作为字典的键
locations = {(0, 0): "原点", (1, 1): "第一象限"}

# 元组可以 unpacking
x, y = point
print(x, y)  # 输出: 3 4

# 函数可以返回多个值(实际上是返回元组)
def get_name_age():
    return "李四", 30

name, age = get_name_age()

字典(Dictionary)

字典是一种可变的、无序的键值对集合。每个键值对由键和值组成,通过键可以快速访问对应的值。

创建字典

# 创建空字典
empty_dict = {}

# 创建包含键值对的字典
student = {"name": "张三", "age": 20, "major": "计算机科学"}
scores = {1: 95, 2: 87, 3: 92}

# 使用dict()函数创建字典
person = dict(name="李四", age=25, city="上海")

# 使用键值对列表创建字典
items = [("name", "王五"), ("age", 22)]
info = dict(items)

访问和修改字典

student = {"name": "张三", "age": 20, "major": "计算机科学"}

# 通过键访问值
print(student["name"])     # 输出: 张三

# 使用get()方法(更安全)
print(student.get("name"))         # 输出: 张三
print(student.get("grade", "N/A")) # 输出: N/A(键不存在时返回默认值)

# 修改值
student["age"] = 21

# 添加新的键值对
student["grade"] = "大二"

# 删除键值对
del student["major"]
removed_value = student.pop("age")  # 删除并返回值
student.clear()  # 清空字典

字典常用方法

student = {"name": "张三", "age": 20, "major": "计算机科学"}

# 获取所有键、值、键值对
keys = student.keys()
values = student.values()
items = student.items()

# 检查键是否存在
if "name" in student:
    print("姓名:", student["name"])

# 更新字典
additional_info = {"city": "北京", "phone": "123456789"}
student.update(additional_info)

# 字典推导式
squares = {x: x**2 for x in range(5)}
print(squares)  # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

遍历字典

student = {"name": "张三", "age": 20, "major": "计算机科学"}

# 遍历键
for key in student:
    print(key)

# 遍历值
for value in student.values():
    print(value)

# 遍历键值对
for key, value in student.items():
    print(f"{key}: {value}")

集合(Set)

集合是一个无序的不重复元素序列。集合支持数学上的集合运算,如并集、交集、差集等。

创建集合

# 创建空集合
empty_set = set()  # 注意不能用{}

# 创建包含元素的集合
numbers = {1, 2, 3, 4, 5}
fruits = {"苹果", "香蕉", "橙子"}

# 使用set()函数创建集合
chars = set("hello")  # {'h', 'e', 'l', 'o'}

集合操作

set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 添加和删除元素
set1.add(6)
set1.remove(1)      # 如果元素不存在会报错
set1.discard(10)    # 如果元素不存在不会报错
popped = set1.pop() # 随机删除并返回一个元素

# 集合运算
union = set1 | set2        # 并集
intersection = set1 & set2 # 交集
difference = set1 - set2   # 差集
symmetric_diff = set1 ^ set2  # 对称差集

# 使用方法形式
union = set1.union(set2)
intersection = set1.intersection(set2)
difference = set1.difference(set2)

# 子集和超集
set3 = {1, 2}
print(set3.issubset(set1))  # 检查是否为子集
print(set1.issuperset(set3))  # 检查是否为超集

集合的特点

# 自动去重
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_numbers = list(set(numbers))
print(unique_numbers)  # 输出: [1, 2, 3, 4](顺序可能不同)

# 成员检查(比列表快)
large_set = set(range(1000000))
print(999999 in large_set)  # 非常快的检查

代码示例与实战

示例1:学生成绩管理系统

class StudentManager:
    def __init__(self):
        self.students = {}  # 使用字典存储学生信息
    
    def add_student(self, student_id, name, scores=None):
        """添加学生"""
        if scores is None:
            scores = []
        self.students[student_id] = {
            "name": name,
            "scores": scores
        }
        print(f"已添加学生: {name} (ID: {student_id})")
    
    def add_score(self, student_id, score):
        """为学生添加成绩"""
        if student_id in self.students:
            self.students[student_id]["scores"].append(score)
            print(f"已为学生 {self.students[student_id]['name']} 添加成绩: {score}")
        else:
            print("学生不存在")
    
    def get_average(self, student_id):
        """计算学生平均成绩"""
        if student_id in self.students:
            scores = self.students[student_id]["scores"]
            if scores:
                return sum(scores) / len(scores)
            else:
                return 0
        else:
            return None
    
    def get_top_students(self, n=3):
        """获取成绩最好的n名学生"""
        averages = []
        for student_id, info in self.students.items():
            avg = self.get_average(student_id)
            if avg > 0:  # 只考虑有成绩的学生
                averages.append((info["name"], avg))
        
        # 按平均分降序排序
        averages.sort(key=lambda x: x[1], reverse=True)
        return averages[:n]
    
    def display_all_students(self):
        """显示所有学生信息"""
        if not self.students:
            print("暂无学生信息")
            return
        
        print("\n=== 学生信息 ===")
        for student_id, info in self.students.items():
            avg = self.get_average(student_id)
            print(f"ID: {student_id}, 姓名: {info['name']}, "
                  f"成绩: {info['scores']}, 平均分: {avg:.2f}")
        print("=" * 30)

def main():
    manager = StudentManager()
    
    # 添加学生
    manager.add_student("001", "张三")
    manager.add_student("002", "李四")
    manager.add_student("003", "王五")
    
    # 添加成绩
    manager.add_score("001", 85)
    manager.add_score("001", 92)
    manager.add_score("002", 78)
    manager.add_score("002", 88)
    manager.add_score("003", 95)
    manager.add_score("003", 87)
    
    # 显示所有学生
    manager.display_all_students()
    
    # 显示前三名学生
    top_students = manager.get_top_students(3)
    print("\n=== 成绩排名 ===")
    for i, (name, avg) in enumerate(top_students, 1):
        print(f"第{i}名: {name}, 平均分: {avg:.2f}")

if __name__ == "__main__":
    main()

示例2:词汇统计器

import string

def analyze_text(text):
    """分析文本,统计词汇信息"""
    # 转换为小写并移除标点符号
    translator = str.maketrans('', '', string.punctuation)
    clean_text = text.lower().translate(translator)
    
    # 分割成单词列表
    words = clean_text.split()
    
    # 使用字典统计词频
    word_count = {}
    for word in words:
        word_count[word] = word_count.get(word, 0) + 1
    
    # 使用集合找出唯一词汇
    unique_words = set(words)
    
    # 统计信息
    total_words = len(words)
    unique_word_count = len(unique_words)
    
    # 找出最常见的词汇
    most_common = sorted(word_count.items(), key=lambda x: x[1], reverse=True)[:5]
    
    return {
        "total_words": total_words,
        "unique_words": unique_word_count,
        "word_count": word_count,
        "unique_word_set": unique_words,
        "most_common": most_common
    }

def display_analysis(analysis):
    """显示分析结果"""
    print("=== 文本分析结果 ===")
    print(f"总词数: {analysis['total_words']}")
    print(f"唯一词汇数: {analysis['unique_words']}")
    print(f"词汇重复率: {(analysis['total_words'] - analysis['unique_words']) / analysis['total_words'] * 100:.2f}%")
    
    print("\n最常见的5个词:")
    for word, count in analysis['most_common']:
        print(f"  {word}: {count}次")
    
    print(f"\n前20个唯一词汇: {list(analysis['unique_word_set'])[:20]}")

def main():
    sample_text = """
    Python is a high-level programming language. Python is easy to learn and powerful.
    It is widely used in web development, data science, artificial intelligence, 
    and many other fields. Python has a simple syntax that makes it readable and 
    maintainable. Many developers love Python because of its versatility and 
    extensive library support.
    """
    
    analysis = analyze_text(sample_text)
    display_analysis(analysis)

if __name__ == "__main__":
    main()

示例3:购物车系统

class ShoppingCart:
    def __init__(self):
        # 使用字典存储商品信息:商品名 -> (价格, 数量)
        self.items = {}
    
    def add_item(self, name, price, quantity=1):
        """添加商品到购物车"""
        if name in self.items:
            # 如果商品已存在,增加数量
            current_price, current_quantity = self.items[name]
            self.items[name] = (price, current_quantity + quantity)
        else:
            # 添加新商品
            self.items[name] = (price, quantity)
        print(f"已添加 {quantity}{name} 到购物车")
    
    def remove_item(self, name, quantity=None):
        """从购物车移除商品"""
        if name not in self.items:
            print(f"购物车中没有 {name}")
            return
        
        current_price, current_quantity = self.items[name]
        
        if quantity is None or quantity >= current_quantity:
            # 移除所有该商品
            del self.items[name]
            print(f"已从购物车移除所有 {name}")
        else:
            # 只移除指定数量
            self.items[name] = (current_price, current_quantity - quantity)
            print(f"已从购物车移除 {quantity}{name}")
    
    def update_quantity(self, name, new_quantity):
        """更新商品数量"""
        if name in self.items:
            current_price, _ = self.items[name]
            if new_quantity <= 0:
                del self.items[name]
                print(f"已从购物车移除 {name}")
            else:
                self.items[name] = (current_price, new_quantity)
                print(f"已更新 {name} 的数量为 {new_quantity}")
        else:
            print(f"购物车中没有 {name}")
    
    def get_total_price(self):
        """计算总价"""
        total = 0
        for price, quantity in self.items.values():
            total += price * quantity
        return total
    
    def display_cart(self):
        """显示购物车内容"""
        if not self.items:
            print("购物车为空")
            return
        
        print("\n=== 购物车 ===")
        total_items = 0
        for name, (price, quantity) in self.items.items():
            subtotal = price * quantity
            print(f"{name}: ¥{price:.2f} x {quantity} = ¥{subtotal:.2f}")
            total_items += quantity
        
        print("-" * 30)
        print(f"总计: ¥{self.get_total_price():.2f} ({total_items} 件商品)")
        print("=" * 30)

def main():
    cart = ShoppingCart()
    
    # 添加商品
    cart.add_item("苹果", 5.0, 3)
    cart.add_item("香蕉", 3.5, 2)
    cart.add_item("橙子", 4.0, 5)
    cart.add_item("苹果", 5.0, 2)  # 再添加苹果
    
    # 显示购物车
    cart.display_cart()
    
    # 更新数量
    cart.update_quantity("香蕉", 5)
    
    # 移除部分商品
    cart.remove_item("橙子", 2)
    
    # 再次显示购物车
    cart.display_cart()

if __name__ == "__main__":
    main()

小结与回顾

在本章中,我们深入学习了Python中的四种主要内置数据结构:

  1. 列表(List)

    • 有序、可变的数据集合
    • 支持索引、切片、增删改查等操作
    • 提供丰富的内置方法
    • 支持列表推导式
  2. 元组(Tuple)

    • 有序、不可变的数据集合
    • 可以作为字典的键
    • 支持unpacking操作
    • 比列表更节省内存
  3. 字典(Dictionary)

    • 键值对数据结构
    • 通过键快速访问值
    • 支持各种集合操作
    • 提供高效的查找性能
  4. 集合(Set)

    • 无序、不重复元素集合
    • 支持数学集合运算
    • 自动去重功能
    • 快速成员检查

通过实际的代码示例,我们不仅掌握了这些数据结构的基本用法,还学会了如何在实际项目中应用它们。正确选择和使用数据结构是编写高效Python程序的关键。

在下一章中,我们将学习面向对象编程的基础知识,包括类和对象的概念,这将帮助我们编写更加模块化和可维护的代码。

练习与挑战

基础练习

  1. 创建一个程序,使用列表存储一周的天气温度,计算平均温度、最高温度和最低温度。
  2. 编写一个函数,接受一个字符串列表,返回其中最长的字符串。
  3. 创建一个字典来存储国家和首都的对应关系,实现添加、查询、删除功能。
  4. 编写一个程序,使用集合找出两个文本文件中的共同词汇。

进阶挑战

  1. 实现一个简单的图书馆管理系统,使用字典存储图书信息,支持借阅、归还、查询等功能。
  2. 创建一个联系人管理系统,使用列表和字典的组合来存储联系人信息,支持增删改查。
  3. 编写一个程序,模拟电商网站的商品分类系统,使用嵌套字典和列表来组织商品数据。
  4. 实现一个简单的任务管理系统,使用列表存储任务,支持任务的添加、完成、删除和优先级排序。

思考题

  1. 在什么情况下应该使用列表而不是元组?
  2. 字典和列表在性能上有何区别?分别适用于什么场景?
  3. 集合相比列表有哪些优势?在什么情况下使用集合更合适?
  4. 如何选择合适的数据结构来优化程序性能?

扩展阅读

  1. Python官方文档 - 数据结构 - 官方文档中关于内置数据结构的详细介绍
  2. Python官方文档 - 序列类型 - 列表和元组的详细说明
  3. Python官方文档 - 映射类型 - 字典的详细说明
  4. Python官方文档 - 集合类型 - 集合的详细说明
  5. 《流畅的Python》- 深入理解Python数据结构的经典书籍
  6. Real Python - Python Data Structures - 关于Python数据结构的详细教程

通过本章的学习,你应该已经掌握了Python中四种主要数据结构的特点和使用方法。这些知识将帮助你更有效地组织和处理数据。在下一章中,我们将学习面向对象编程的基础知识,这是现代编程的重要范式。