数据结构高级操作|第三部分:流程控制与数据结构操作 (Control Flow & Data Structures Manipulation)

发布于 2025-09-11 分类: Python
系列文章: Python全方位教程
第 1 部分: Python语言概览|第一部分:Python入门与环境搭建 (Python Foundations) 第 2 部分: 搭建开发环境|第一部分:Python入门与环境搭建 (Python Foundations) 第 3 部分: Python基本语法与规范|第一部分:Python入门与环境搭建 (Python Foundations) 第 4 部分: 数据类型深入解析|第二部分:Python核心数据类型与运算符 (Core Data Types & Operators) 第 5 部分: 运算符大全|第二部分:Python核心数据类型与运算符 (Core Data Types & Operators) 第 6 部分: 条件与循环|第三部分:流程控制与数据结构操作 (Control Flow & Data Structures Manipulation) 第 7 部分: 数据结构高级操作|第三部分:流程控制与数据结构操作 (Control Flow & Data Structures Manipulation) (当前) 第 8 部分: 函数|第四部分:函数、模块与代码组织 (Functions, Modules & Code Organization) 第 9 部分: 模块与包|第四部分:函数、模块与代码组织 (Functions, Modules & Code Organization) 第 10 部分: 类与对象|第五部分:面向对象编程 (Object-Oriented Programming - OOP) 第 11 部分: OOP核心特性|第五部分:面向对象编程 (Object--Oriented Programming - OOP) 第 12 部分: 高级OOP主题|第五部分:面向对象编程 (Object-Oriented Programming - OOP) 第 13 部分: 迭代与生成|第六部分:高级Python编程 (Advanced Python) 第 15 部分: 内存管理与性能|第六部分:高级Python编程 (Advanced Python) 第 16 部分: 文件与目录操作|第七部分:Python标准库精选 (The Standard Library) 第 17 部分: 数据处理与序列化|第七部分:Python标准库精选 (The Standard Library) 第 18 部分: 网络与并发编程|第七部分:Python标准库精选 (The Standard Library) 第 20 部分: 系统交互|第七部分:Python标准库精选 (The Standard Library) 第 21 部分: 数据科学与分析入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 22 部分: Web开发入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 23 部分: GUI编程入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 24 部分: 图像处理入门|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 25 部分: 自动化脚本|第八部分:Python生态与实战应用 (Ecosystem & Applications) 第 26 部分: Python备忘单 (Cheatsheet)|第九部分:附录与资源 (Appendix & Resources) 第 27 部分: 常见面试题与解答|第九部分:附录与资源 (Appendix & Resources) 第 28 部分: 官方文档与其他学习资源链接|第九部分:附录与资源 (Appendix & Resources)

欢迎来到你的“兵器”精通课程!在之前的旅程中,我们认识了字符串、列表、字典等基本“兵器”。现在,你已经学会了 iffor 这些内功心法,是时候将它们与兵器结合,施展出令人眼花缭乱的“高级招式”了。

本章将带你深入每一种数据结构的内部,探索那些能让你代码效率倍增、可读性飙升的技巧。你将学会如何像切蛋糕一样精准地切割数据(切片),如何用一行代码创造一个列表(推导式),以及如何复制数据而不引发“连锁反应”(深浅拷贝)。这些技巧,是区分Python新手和高手的真正分水岭。准备好,让你的数据处理能力发生质的飞跃吧!

7.1 字符串: 不只是文本,更是艺术

字符串是不可变的,但这并不妨碍我们对它进行各种花哨的操作,每次操作都会产生一个新的、为你量身定制的字符串。

  • 索引与切片 (Slicing): 这是Python最优雅的特性之一。你可以像取书架上的书一样,精确地取出字符串的任何部分。

    • 索引: string[index],从0开始。负数索引表示从后往前数,-1 是最后一个字符。
    • 切片: string[start:stop:step],一个“顾头不顾尾”的操作,包含start索引,但不包含stop索引。
    s = "Hello, Python!"
    
    # 索引
    print(s[0])   # 输出: H
    print(s[-1])  # 输出: !
    
    # 切片
    print(s[7:13]) # 输出: Python (从索引7到12)
    print(s[:5])   # 输出: Hello (从开头到索引4)
    print(s[7:])   # 输出: Python! (从索引7到结尾)
    print(s[::-1]) # 终极技巧:步长为-1,轻松反转字符串! -> !nohtyP ,olleH
    
  • 格式化 (f-string): 这是现代Python(3.6+)中最推荐的字符串格式化方式。它就像一个“填空题”模板,直观、高效、强大。

    name = "Alice"
    age = 30
    
    # 使用 f-string
    message = f"大家好,我叫 {name},我今年 {age} 岁了。"
    print(message) # 输出: 大家好,我叫 Alice,我今年 30 岁了。
    
    # 甚至可以在 {} 中执行简单的表达式
    print(f"{name} 明年就 {age + 1} 岁了。") # 输出: Alice 明年就 31 岁了。
    
  • 常用方法: 字符串自带了大量超级有用的“工具函数”。

    • .strip(): 去除首尾的空白字符。
    • .upper() / .lower(): 转换为大写/小写。
    • .replace(old, new): 替换子字符串。
    • .split(separator): 按分隔符分割字符串,返回一个列表。
    • separator.join(iterable): 用指定分隔符连接一个序列中的所有元素。
    text = "  python is awesome  "
    print(text.strip())          # 输出: "python is awesome"
    print(text.upper())          # 输出: "  PYTHON IS AWESOME  "
    print(text.replace("awesome", "fun")) # 输出: "  python is fun  "
    
    csv_data = "apple,banana,cherry"
    fruits_list = csv_data.split(',')
    print(fruits_list)           # 输出: ['apple', 'banana', 'cherry']
    
    print(" | ".join(fruits_list)) # 输出: "apple | banana | cherry"
    

7.2 列表: 你的动态数据瑞士军刀

列表是可变的,这意味着我们可以随心所欲地对它进行增、删、改、查。

  • 增删改查 (CRUD)

    • : .append(item) (在末尾添加), .insert(index, item) (在指定位置插入)
    • : .pop(index) (删除并返回指定位置元素,默认为最后一个), .remove(value) (删除第一个匹配的元素), del my_list[index] (删除指定位置元素)
    • : my_list[index] = new_value
    • : my_list[index]
    nums = [1, 2, 3]
    nums.append(4)      # [1, 2, 3, 4]
    nums.insert(1, 99)  # [1, 99, 2, 3, 4]
    
    removed_item = nums.pop() # removed_item is 4, nums is [1, 99, 2, 3]
    nums.remove(99)     # [1, 2, 3]
    
    nums[1] = 200       # [1, 200, 3]
    print(nums)
    
  • 排序:

    • my_list.sort(): 原地排序,会直接修改原始列表。
    • sorted(my_list): 返回一个新的排好序的列表,不改变原始列表。
    scores = [88, 56, 97, 73]
    
    # 使用 sorted()
    sorted_scores = sorted(scores)
    print(f"原始列表: {scores}")        # 输出: [88, 56, 97, 73]
    print(f"排序后的新列表: {sorted_scores}") # 输出: [56, 73, 88, 97]
    
    # 使用 .sort()
    scores.sort(reverse=True) # reverse=True 实现降序排序
    print(f"原地排序后的列表: {scores}") # 输出: [97, 88, 73, 56]
    
  • 复制(浅拷贝与深拷贝): 这是一个非常重要的概念!

    • 直接赋值: b = a,这只是给同一个列表起了个别名,修改b会影响a
    • 浅拷贝 (Shallow Copy): b = a.copy()b = a[:]。会创建一个新列表,但如果列表内包含其他可变对象(如子列表),则只复制这些对象的引用。
    • 深拷贝 (Deep Copy): 需要 import copy; b = copy.deepcopy(a)。会递归地复制所有内容,创建一个完全独立的新对象。
    # 浅拷贝的“陷阱”
    import copy
    
    list_a = [1, 2, [10, 20]]
    list_b = list_a.copy() # 浅拷贝
    
    list_b.append(3)       # 修改 list_b 的外层,不影响 list_a
    list_b[2].append(30)   # 修改 list_b 中嵌套列表的内容
    
    print(f"List A: {list_a}") # 输出: List A: [1, 2, [10, 20, 30]] <-- 被影响了!
    print(f"List B: {list_b}") # 输出: List B: [1, 2, [10, 20, 30], 3]
    
    # 深拷贝解决问题
    list_c = copy.deepcopy(list_a)
    list_c[2].append(40)
    print(f"List A (after deepcopy change): {list_a}") # 输出: List A (after deepcopy change): [1, 2, [10, 20, 30]] <-- 未受影响!
    print(f"List C: {list_c}") # 输出: List C: [1, 2, [10, 20, 30, 40]]
    
  • 列表推导式 (List Comprehension): Python的“语法糖”之王!它能让你用一行代码,基于现有列表创建一个新列表,优雅且高效。
    基本语法: [expression for item in iterable if condition]

    # 传统方法:创建一个0-9的平方数列表
    squares = []
    for i in range(10):
        squares.append(i * i)
    print(squares)
    
    # 列表推导式:一行搞定!
    squares_comp = [i * i for i in range(10)]
    print(squares_comp)
    
    # 加上条件:只取偶数的平方
    even_squares = [i * i for i in range(10) if i % 2 == 0]
    print(even_squares) # 输出: [0, 4, 16, 36, 64]
    

7.3 元组: 不可变性带来的妙用

虽然元组不能修改,但它在“解构”数据方面有奇效。

  • 打包与解包 (Packing & Unpacking):

    • 打包: 将多个值“打包”成一个元组。my_tuple = 1, "a", True
    • 解包: 将元组中的元素一次性赋给多个变量。
    # 打包
    point = (100, 200)
    
    # 解包
    x, y = point
    print(f"x坐标: {x}, y坐标: {y}") # 输出: x坐标: 100, y坐标: 200
    
    # 这个技巧常用于函数返回多个值
    def get_user_info():
        return "Bob", 35, "USA"
    
    name, age, country = get_user_info()
    
  • 命名元组 (namedtuple): 当你觉得用 point[0] point[1] 这样的索引来访问元组元素不够直观时,namedtuple 就是你的救星。它能给元组的每个位置起个名字。

    from collections import namedtuple
    
    # 创建一个名为 "Point" 的命名元组模板
    Point = namedtuple("Point", ["x", "y"])
    
    # 使用模板创建实例
    p1 = Point(10, 20)
    
    print(p1.x) # 输出: 10 (比 p1[0] 可读性强多了!)
    print(p1.y) # 输出: 20
    

7.4 字典: 键值对的终极玩法

  • 增删改查:

    • : my_dict.get(key, default_value) 是比 my_dict[key] 更安全的方式,当键不存在时,它不会报错,而是返回你指定的默认值(默认为None)。
    • : del my_dict[key]my_dict.pop(key)
    person = {"name": "Charlie"}
    print(person.get("age", 18)) # 输出: 18 (age不存在,返回默认值18)
    # print(person["age"]) # 这行会直接报错 KeyError
    
  • 遍历: for 循环可以优雅地遍历字典。

    • .keys(): 遍历所有的键。
    • .values(): 遍历所有的值。
    • .items(): 最常用,同时遍历键和值。
    user = {"name": "David", "id": 101, "role": "admin"}
    
    # 遍历键值对
    for key, value in user.items():
        print(f"{key}: {value}")
    
  • 视图对象 (keys(), values(), items()): 这些方法返回的不是列表,而是一个“视图”。视图是动态的,如果原始字典发生变化,视图会立即反映这些变化。

  • 嵌套字典: 字典可以包含其他字典,形成复杂的数据结构,这在处理JSON等数据时非常常见。

    users = {
        "user1": {"name": "Eve", "age": 22},
        "user2": {"name": "Frank", "age": 29}
    }
    print(users["user2"]["name"]) # 输出: Frank
    

7.5 集合: 数学运算的利器

集合的核心在于它的数学特性:并集、交集、差集等。

  • 增删改查: .add(item), .remove(item) (若元素不存在会报错), .discard(item) (若元素不存在不会报错)。

  • 数学运算:

    • 并集: set_a | set_bset_a.union(set_b)
    • 交集: set_a & set_bset_a.intersection(set_b)
    • 差集: set_a - set_bset_a.difference(set_b)
    • 对称差集: set_a ^ set_bset_a.symmetric_difference(set_b) (两个集合中不重复的元素)
    devs = {"Alice", "Bob", "Charlie"}
    ops = {"Charlie", "David", "Eve"}
    
    print(f"所有员工: {devs | ops}")
    print(f"既是开发又是运维: {devs & ops}")
    print(f"只是开发人员: {devs - ops}")
    print(f"只属于一个部门的员工: {devs ^ ops}")
    

7.6 数组: array 模块的使用

Python的列表可以存放不同类型的元素,非常灵活,但这也意味着额外的内存开销。如果你需要存储大量的同类型数值数据(如整数或浮点数),使用 array 模块会更节省内存

注意: 在数据科学领域,NumPy 库的 array 是绝对的主流和首选。这里的 array 模块是Python内置的一个轻量级替代品。

import array

# 'i' 是一个类型码,表示有符号整数
int_array = array.array('i', [1, 2, 3, 4, 5])
print(int_array)
print(int_array[2]) # 输出: 3

# 尝试添加一个非整数类型
# int_array.append(3.14) # 这会引发 TypeError

难以置信!你已经从一个数据结构的“使用者”升级为了“驾驭者”。你现在拥有的这些高级技巧——切片、推导式、深拷贝、解包等等——将使你的代码更加简洁、高效和专业。你已经具备了处理复杂数据的坚实基础。

但是,当我们写的代码越来越多,逻辑越来越复杂时,如何将这些强大的操作组织起来,让它们可以被复用,让整个项目保持清晰和整洁呢?答案就是函数模块。在下一章,我们将学习如何将代码打包成可重用的“积木”,开启构建大型程序的宏伟篇章!准备好,成为一名真正的“代码建筑师”吧!


-- 感谢阅读 --