第4章 数据结构

前言

Python提供了丰富的内置数据结构,包括字符串(String)、列表(List)、元组(Tuple)、字典(Dictionary)和集合(Set)。这些数据结构各有特点,适用于不同的应用场景。掌握这些数据结构的使用方法和特性,是Python编程的基础。本章将详细介绍每种数据结构的创建、操作和应用,并通过大量的实例代码帮助读者理解和掌握。

本系列文章所使用到的示例源码:Python从入门到精通示例代码

4.1 字符串(String)

4.1.1 字符串基础操作

字符串的定义与创建

Python中字符串可以用单引号、双引号或三引号来定义。三引号通常用于多行字符串。

# 字符串的创建方式
single_quote = 'Hello World'
double_quote = "Hello World"
triple_quote = """这是一个
多行字符串
示例"""

# 原始字符串(r-string)- 不转义特殊字符
raw_string = r'C:\Users\Python\test.txt'

# 字节字符串(b-string)
byte_string = b'Hello World'

print("单引号字符串:", single_quote)
print("双引号字符串:", double_quote)
print("三引号字符串:")
print(triple_quote)
print("原始字符串:", raw_string)
print("字节字符串:", byte_string)
print("字节字符串类型:", type(byte_string))

输出结果:

单引号字符串: Hello World
双引号字符串: Hello World
三引号字符串:
这是一个
多行字符串
示例
原始字符串: C:\Users\Python\test.txt
字节字符串: b'Hello World'
字节字符串类型: <class 'bytes'>

字符串的索引与切片

字符串支持正向索引(从0开始)和负向索引(从-1开始),还支持切片操作。

# 字符串索引和切片示例
text = "Python编程"

# 正向索引
print("第一个字符:", text[0])  # P
print("第二个字符:", text[1])  # y

# 负向索引
print("最后一个字符:", text[-1])  # 程
print("倒数第二个字符:", text[-2])  # 编

# 切片操作 [start:end:step]
print("前3个字符:", text[:3])  # Pyt
print("从第2个到第5个字符:", text[2:6])  # thon
print("最后3个字符:", text[-3:])  # n编程
print("每隔一个字符:", text[::2])  # Pto编
print("反转字符串:", text[::-1])  # 程编nohtyP

输出结果:

第一个字符: P
第二个字符: y
最后一个字符: 
倒数第二个字符: 
3个字符: Pyt
从第2个到第5个字符: thon
最后3个字符: n编程
每隔一个字符: Pto编
反转字符串: 程编nohtyP

字符串的基本操作

# 字符串基本操作示例
str1 = "Hello"
str2 = "World"

# 长度获取
print("str1长度:", len(str1))  # 5

# 字符串连接
result1 = str1 + " " + str2
print("连接结果:", result1)  # Hello World

# 字符串重复
result2 = str1 * 3
print("重复结果:", result2)  # HelloHelloHello

# 成员检测
print("'ell' in str1:", 'ell' in str1)  # True
print("'xyz' not in str1:", 'xyz' not in str1)  # True

# 字符串的不可变性演示
original = "Python"
print("原始字符串:", original)
# original[0] = 'J'  # 这行代码会报错,因为字符串不可变
modified = 'J' + original[1:]  # 正确的修改方式
print("修改后的字符串:", modified)

输出结果:

str1长度: 5
连接结果: Hello World
重复结果: HelloHelloHello
'ell' in str1: True
'xyz' not in str1: True
原始字符串: Python
修改后的字符串: Jython

4.1.2 字符串格式化

Python提供了多种字符串格式化方式,从传统的%操作符到现代的f-string。

传统格式化(%操作符)

# 传统格式化示例
name = "张三"
age = 25
height = 175.5

# 基本格式化
print("姓名: %s, 年龄: %d, 身高: %.1f厘米" % (name, age, height))

# 格式化参数控制
print("浮点数: %10.2f" % 3.1415926)  # 宽度10,精度2
print("整数补零: %05d" % 42)  # 宽度5,补零
print("左对齐: %-10s" % "Python")  # 宽度10,左对齐

输出结果:

姓名: 张三, 年龄: 25, 身高: 175.5厘米
浮点数:       3.14
整数补零: 00042
左对齐: Python    

str.format()方法

# str.format()方法示例
name = "李四"
age = 30

# 位置参数
print("姓名: {}, 年龄: {}".format(name, age))

# 索引参数
print("年龄: {1}, 姓名: {0}".format(name, age))

# 关键字参数
print("姓名: {name}, 年龄: {age}".format(name=name, age=age))

# 格式化规范
pi = 3.1415926
print("数字格式化: {:.2f}".format(pi))  # 保留2位小数
print("百分比: {:.1%}".format(0.25))  # 百分比格式,保留1位小数
print("科学计数法: {:.2e}".format(1000000))  # 科学计数法,保留2位小数
print("千位分隔符: {:,}".format(1234567))  # 添加千位分隔符

输出结果:

姓名: 李四, 年龄: 30
年龄: 30, 姓名: 李四
姓名: 李四, 年龄: 30
数字格式化: 3.14
百分比: 25.0%
科学计数法: 1.00e+06
千位分隔符: 1,234,567

f-string格式化(推荐)

f-string是Python 3.6引入的新特性,是目前最推荐的字符串格式化方式。

# f-string格式化示例
name = "王五"
age = 35
height = 180.5

# 基本语法
print(f"姓名: {name}, 年龄: {age}, 身高: {height}厘米")

# 表达式嵌入
print(f"年龄5年后: {age + 5}")
print(f"身高(英尺): {height / 30.48:.2f}")

# 格式化选项
pi = 3.1415926
print(f"π值: {pi:.4f}")  # 保留4位小数
print(f"大数字: {1000000:,}")  # 添加千位分隔符
print(f"二进制: {42:b}")  # 二进制表示
print(f"十六进制: {42:x}")  # 十六进制表示
print(f"居中对齐: {name:^10}")  # 居中对齐,宽度10

输出结果:

姓名: 王五, 年龄: 35, 身高: 180.5厘米
年龄5年后: 40
身高(英尺): 5.92
π值: 3.1416
大数字: 1,000,000
二进制: 101010
十六进制: 2a
居中对齐:    王五   

4.1.3 字符串方法详解

Python的字符串类型提供了丰富的方法,可以方便地进行各种操作。

大小写转换方法

# 大小写转换方法示例
text = "Hello, World!"

print("原始字符串:", text)
print("全部大写:", text.upper())
print("全部小写:", text.lower())
print("首字母大写:", text.capitalize())
print("每个单词首字母大写:", text.title())
print("大小写互换:", text.swapcase())

输出结果:

原始字符串: Hello, World!
全部大写: HELLO, WORLD!
全部小写: hello, world!
首字母大写: Hello, world!
每个单词首字母大写: Hello, World!
大小写互换: hELLO, wORLD!

查找和替换方法

# 查找和替换方法示例
text = "Python编程语言是一种易学易用的编程语言"

# 查找方法
print("'编程'第一次出现的位置:", text.find("编程"))  # 返回索引,如果不存在返回-1
print("'编程'最后一次出现的位置:", text.rfind("编程"))  # 从右侧开始查找
print("'Java'是否存在:", text.find("Java"))  # 不存在,返回-1

try:
    print("使用index查找'编程':", text.index("编程"))  # 返回索引,如果不存在抛出异常
    print("使用index查找'Java':", text.index("Java"))  # 不存在,抛出异常
except ValueError as e:
    print(f"捕获到异常: {e}")

# 计数方法
print("'编程'出现的次数:", text.count("编程"))  # 返回出现次数

# 替换方法
print("替换'编程'为'开发':", text.replace("编程", "开发"))
print("替换'编程'为'开发'(只替换一次):", text.replace("编程", "开发", 1))  # 限制替换次数

输出结果:

'编程'第一次出现的位置: 6
'编程'最后一次出现的位置: 18
'Java'是否存在: -1
使用index查找'编程': 6
捕获到异常: substring not found
'编程'出现的次数: 2
替换'编程'为'开发': Python开发语言是一种易学易用的开发语言
替换'编程'为'开发'(只替换一次): Python开发语言是一种易学易用的编程语言

判断方法

# 判断方法示例
text1 = "Hello123"
text2 = "PYTHON"
text3 = "  \t\n"
text4 = "Python"

# 内容判断
print(f"'{text1}' 是否为字母和数字: {text1.isalnum()}")
print(f"'{text1}' 是否全为字母: {text1.isalpha()}")
print(f"'{text1}' 是否全为数字: {text1.isdigit()}")
print(f"'123' 是否全为数字: {'123'.isdigit()}")

# 大小写判断
print(f"'{text2}' 是否全为大写: {text2.isupper()}")
print(f"'{text4}' 是否全为小写: {text4.islower()}")

# 空白判断
print(f"'{text3}' 是否全为空白字符: {text3.isspace()}")

# 前缀后缀判断
print(f"'{text4}' 是否以'Py'开头: {text4.startswith('Py')}")
print(f"'{text4}' 是否以'on'结尾: {text4.endswith('on')}")

输出结果:

'Hello123' 是否为字母和数字: True
'Hello123' 是否全为字母: False
'Hello123' 是否全为数字: False
'123' 是否全为数字: True
'PYTHON' 是否全为大写: True
'Python' 是否全为小写: False
'   
' 是否全为空白字符: True
'Python' 是否以'Py'开头: True
'Python' 是否以'on'结尾: True

分割和连接方法

# 分割和连接方法示例
text = "Python,Java,C++,JavaScript"
text_lines = "第一行\n第二行\n第三行"

# 分割方法
print("按逗号分割:", text.split(","))  # 按指定分隔符分割
print("按逗号分割(限制2次):", text.split(",", 2))  # 限制分割次数
print("按行分割:\n", text_lines.splitlines())  # 按行分割

# 连接方法
words = ["Python", "是", "一种", "编程语言"]
print("使用空格连接:", " ".join(words))  # 使用指定字符连接列表元素
print("使用-连接:", "-".join(words))

输出结果:

按逗号分割: ['Python', 'Java', 'C++', 'JavaScript']
按逗号分割(限制2次): ['Python', 'Java', 'C++,JavaScript']
按行分割:
 ['第一行', '第二行', '第三行']
使用空格连接: Python 是 一种 编程语言
使用-连接: Python-是-一种-编程语言

去除空白方法

# 去除空白方法示例
text = "  Python编程  "

print(f"原始字符串: '{text}'")
print(f"去除两端空白: '{text.strip()}'")
print(f"去除左侧空白: '{text.lstrip()}'")
print(f"去除右侧空白: '{text.rstrip()}'")

# 去除指定字符
text2 = "###Python###"
print(f"原始字符串: '{text2}'")
print(f"去除两端#号: '{text2.strip('#')}'")

输出结果:

原始字符串: '  Python编程  '
去除两端空白: 'Python编程'
去除左侧空白: 'Python编程  '
去除右侧空白: '  Python编程'
原始字符串: '###Python###'
去除两端#号: 'Python'

4.2 列表(List)

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

4.2.1 列表的创建与访问

列表的定义与特点

列表具有以下特点:
- 有序:元素有固定的位置
- 可变:可以修改、添加、删除元素
- 允许重复:同一个值可以出现多次
- 异构:可以存储不同类型的数据

# 列表的创建方法示例
# 直接创建
fruits = ["苹果", "香蕉", "橙子"]
numbers = [1, 2, 3, 4, 5]
mixed_list = ["Python", 3.14, True, [1, 2, 3]]  # 混合类型

# list()构造函数
list1 = list()  # 空列表
list2 = list("Python")  # 从字符串创建
list3 = list(range(5))  # 从range对象创建

# 列表推导式(简介)
squares = [x**2 for x in range(5)]  # 生成平方数列表

print("水果列表:", fruits)
print("数字列表:", numbers)
print("混合列表:", mixed_list)
print("空列表:", list1)
print("从字符串创建:", list2)
print("从range创建:", list3)
print("平方数列表:", squares)

输出结果:

水果列表: ['苹果', '香蕉', '橙子']
数字列表: [1, 2, 3, 4, 5]
混合列表: ['Python', 3.14, True, [1, 2, 3]]
空列表: []
从字符串创建: ['P', 'y', 't', 'h', 'o', 'n']
从range创建: [0, 1, 2, 3, 4]
平方数列表: [0, 1, 4, 9, 16]
列表的索引与切片
# 列表索引和切片示例
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]

# 单个元素访问
print("第一个元素:", fruits[0])  # 苹果
print("最后一个元素:", fruits[-1])  # 西瓜

# 切片操作
print("前三个元素:", fruits[:3])  # ['苹果', '香蕉', '橙子']
print("从第二个到第四个:", fruits[1:4])  # ['香蕉', '橙子', '葡萄']
print("最后两个元素:", fruits[-2:])  # ['葡萄', '西瓜']
print("每隔一个元素:", fruits[::2])  # ['苹果', '橙子', '西瓜']
print("反转列表:", fruits[::-1])  # ['西瓜', '葡萄', '橙子', '香蕉', '苹果']

# 列表的可变性演示
print("原始列表:", fruits)
fruits[1] = "芒果"  # 修改第二个元素
print("修改后的列表:", fruits)

输出结果:

第一个元素: 苹果
最后一个元素: 西瓜
前三个元素: ['苹果', '香蕉', '橙子']
从第二个到第四个: ['香蕉', '橙子', '葡萄']
最后两个元素: ['葡萄', '西瓜']
每隔一个元素: ['苹果', '橙子', '西瓜']
反转列表: ['西瓜', '葡萄', '橙子', '香蕉', '苹果']
原始列表: ['苹果', '香蕉', '橙子', '葡萄', '西瓜']
修改后的列表: ['苹果', '芒果', '橙子', '葡萄', '西瓜']

4.2.2 列表的增删改查

添加元素
# 列表添加元素示例
fruits = ["苹果", "香蕉"]
print("初始列表:", fruits)

# append()方法 - 在末尾添加单个元素
fruits.append("橙子")
print("append后:", fruits)

# insert()方法 - 在指定位置插入元素
fruits.insert(1, "葡萄")  # 在索引1处插入
print("insert后:", fruits)

# extend()方法 - 添加多个元素
fruits.extend(["西瓜", "芒果"])
print("extend后:", fruits)

# +操作符 - 连接列表(创建新列表)
new_fruits = fruits + ["草莓", "蓝莓"]
print("使用+操作符:", new_fruits)
print("原列表不变:", fruits)

# +=操作符 - 就地扩展
fruits += ["樱桃"]
print("使用+=操作符:", fruits)

输出结果:

初始列表: ['苹果', '香蕉']
append后: ['苹果', '香蕉', '橙子']
insert后: ['苹果', '葡萄', '香蕉', '橙子']
extend后: ['苹果', '葡萄', '香蕉', '橙子', '西瓜', '芒果']
使用+操作符: ['苹果', '葡萄', '香蕉', '橙子', '西瓜', '芒果', '草莓', '蓝莓']
原列表不变: ['苹果', '葡萄', '香蕉', '橙子', '西瓜', '芒果']
使用+=操作符: ['苹果', '葡萄', '香蕉', '橙子', '西瓜', '芒果', '樱桃']
删除元素
# 列表删除元素示例
fruits = ["苹果", "香蕉", "橙子", "葡萄", "香蕉", "西瓜"]
print("初始列表:", fruits)

# del语句 - 按索引删除
del fruits[1]  # 删除索引1的元素
print("del删除后:", fruits)

# remove()方法 - 删除第一个匹配的值
fruits.remove("香蕉")  # 删除第一个"香蕉"
print("remove删除后:", fruits)

# pop()方法 - 删除并返回指定位置的元素
popped = fruits.pop()  # 删除最后一个元素
print(f"pop删除的元素: {popped}")
print("pop删除后:", fruits)

popped_index = fruits.pop(1)  # 删除索引1的元素
print(f"pop删除的元素: {popped_index}")
print("pop删除后:", fruits)

# clear()方法 - 清空列表
temp_list = [1, 2, 3]
print("清空前:", temp_list)
temp_list.clear()
print("清空后:", temp_list)

输出结果:

初始列表: ['苹果', '香蕉', '橙子', '葡萄', '香蕉', '西瓜']
del删除后: ['苹果', '橙子', '葡萄', '香蕉', '西瓜']
remove删除后: ['苹果', '橙子', '葡萄', '西瓜']
pop删除的元素: 西瓜
pop删除后: ['苹果', '橙子', '葡萄']
pop删除的元素: 橙子
pop删除后: ['苹果', '葡萄']
清空前: [1, 2, 3]
清空后: []
修改和查找元素
# 列表修改和查找示例
fruits = ["苹果", "香蕉", "橙子", "葡萄", "香蕉"]
print("初始列表:", fruits)

# 直接赋值修改
fruits[1] = "芒果"
print("修改索引1后:", fruits)

# 切片赋值修改
fruits[1:3] = ["草莓", "蓝莓", "樱桃"]  # 替换索引1-2的元素
print("切片赋值后:", fruits)

# 查找元素
print("'葡萄'的索引:", fruits.index("葡萄"))  # 返回第一个匹配的索引
print("'香蕉'出现的次数:", fruits.count("香蕉"))  # 统计出现次数
print("'苹果'是否在列表中:", "苹果" in fruits)  # 成员检测
print("'西瓜'是否在列表中:", "西瓜" in fruits)

# 处理查找异常
try:
    index = fruits.index("西瓜")
except ValueError:
    print("'西瓜'不在列表中")

输出结果:

初始列表: ['苹果', '香蕉', '橙子', '葡萄', '香蕉']
修改索引1后: ['苹果', '芒果', '橙子', '葡萄', '香蕉']
切片赋值后: ['苹果', '草莓', '蓝莓', '樱桃', '葡萄', '香蕉']
'葡萄'的索引: 4
'香蕉'出现的次数: 1
'苹果'是否在列表中: True
'西瓜'是否在列表中: False
'西瓜'不在列表中

4.2.3 列表的排序与反转

# 列表排序和反转示例
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
fruits = ["香蕉", "苹果", "橙子", "葡萄"]

print("原始数字列表:", numbers)
print("原始水果列表:", fruits)

# sort()方法 - 就地排序
numbers_copy = numbers.copy()
numbers_copy.sort()  # 升序排序
print("升序排序:", numbers_copy)

numbers_copy.sort(reverse=True)  # 降序排序
print("降序排序:", numbers_copy)

# 字符串排序
fruits_copy = fruits.copy()
fruits_copy.sort()  # 按字母顺序排序
print("水果按字母排序:", fruits_copy)

# 自定义排序规则 - 按长度排序
fruits_copy.sort(key=len)
print("水果按长度排序:", fruits_copy)

# sorted()函数 - 返回新的排序列表
sorted_numbers = sorted(numbers)
print("sorted()函数结果:", sorted_numbers)
print("原列表不变:", numbers)

# reverse()方法 - 就地反转
numbers_copy = numbers.copy()
numbers_copy.reverse()
print("reverse()反转:", numbers_copy)

# reversed()函数 - 返回反转迭代器
reversed_list = list(reversed(numbers))
print("reversed()函数结果:", reversed_list)

# 列表复制
original = [1, 2, [3, 4]]
shallow_copy = original.copy()  # 浅拷贝
deep_copy_demo = [1, 2, [3, 4]]

print("\n列表复制演示:")
print("原始列表:", original)
original[2][0] = 99  # 修改嵌套列表
print("修改嵌套元素后:")
print("原始列表:", original)
print("浅拷贝:", shallow_copy)  # 浅拷贝会受影响

输出结果:

原始数字列表: [3, 1, 4, 1, 5, 9, 2, 6]
原始水果列表: ['香蕉', '苹果', '橙子', '葡萄']
升序排序: [1, 1, 2, 3, 4, 5, 6, 9]
降序排序: [9, 6, 5, 4, 3, 2, 1, 1]
水果按字母排序: ['橙子', '苹果', '葡萄', '香蕉']
水果按长度排序: ['苹果', '橙子', '葡萄', '香蕉']
sorted()函数结果: [1, 1, 2, 3, 4, 5, 6, 9]
原列表不变: [3, 1, 4, 1, 5, 9, 2, 6]
reverse()反转: [6, 2, 9, 5, 1, 4, 1, 3]
reversed()函数结果: [6, 2, 9, 5, 1, 4, 1, 3]

列表复制演示:
原始列表: [1, 2, [3, 4]]
修改嵌套元素后:
原始列表: [1, 2, [99, 4]]
浅拷贝: [1, 2, [99, 4]]

4.3 元组(Tuple)

元组是Python中的不可变序列类型,与列表类似但不能修改。元组通常用于存储相关但不同类型的数据。

元组的定义与特点

元组具有以下特点:
- 有序:元素有固定的位置
- 不可变:创建后不能修改元素
- 允许重复:同一个值可以出现多次
- 异构:可以存储不同类型的数据
- 可哈希:可以作为字典的键

# 元组的创建方法示例
# 圆括号创建
point = (3, 4)
colors = ("红色", "绿色", "蓝色")

# 逗号创建(推荐加括号以提高可读性)
single_tuple = (42,)  # 单元素元组,注意逗号
coordinates = 10, 20  # 不加括号也可以

# tuple()构造函数
empty_tuple = tuple()  # 空元组
from_list = tuple([1, 2, 3, 4])  # 从列表创建
from_string = tuple("Python")  # 从字符串创建

print("点坐标:", point)
print("颜色元组:", colors)
print("单元素元组:", single_tuple)
print("坐标:", coordinates)
print("空元组:", empty_tuple)
print("从列表创建:", from_list)
print("从字符串创建:", from_string)
print("元组类型:", type(point))

输出结果:

点坐标: (3, 4)
颜色元组: ('红色', '绿色', '蓝色')
单元素元组: (42,)
坐标: (10, 20)
空元组: ()
从列表创建: (1, 2, 3, 4)
从字符串创建: ('P', 'y', 't', 'h', 'o', 'n')
元组类型: <class 'tuple'>

元组的访问与操作

# 元组访问和操作示例
fruits = ("苹果", "香蕉", "橙子", "葡萄", "西瓜")
numbers = (1, 2, 3, 4, 5, 4, 3, 2, 1)

# 索引访问
print("第一个水果:", fruits[0])  # 苹果
print("最后一个水果:", fruits[-1])  # 西瓜

# 切片操作
print("前三个水果:", fruits[:3])  # ('苹果', '香蕉', '橙子')
print("最后两个水果:", fruits[-2:])  # ('葡萄', '西瓜')
print("每隔一个:", fruits[::2])  # ('苹果', '橙子', '西瓜')

# 元组的不可变性演示
print("原始元组:", fruits)
# fruits[0] = "芒果"  # 这行代码会报错,因为元组不可变

# 但可以重新赋值整个元组
fruits = ("芒果", "香蕉", "橙子", "葡萄", "西瓜")
print("重新赋值后:", fruits)

# 元组的方法
print("数字4出现的次数:", numbers.count(4))  # 统计元素出现次数
print("数字3第一次出现的位置:", numbers.index(3))  # 查找元素索引

# 元组解包
point = (10, 20)
x, y = point  # 解包到变量
print(f"x坐标: {x}, y坐标: {y}")

# 多变量赋值
a, b, c = 1, 2, 3  # 实际上是元组解包
print(f"a={a}, b={b}, c={c}")

输出结果:

第一个水果: 苹果
最后一个水果: 西瓜
前三个水果: ('苹果', '香蕉', '橙子')
最后两个水果: ('葡萄', '西瓜')
每隔一个: ('苹果', '橙子', '西瓜')
原始元组: ('苹果', '香蕉', '橙子', '葡萄', '西瓜')
重新赋值后: ('芒果', '香蕉', '橙子', '葡萄', '西瓜')
数字4出现的次数: 2
数字3第一次出现的位置: 2
x坐标: 10, y坐标: 20
a=1, b=2, c=3

元组的应用场景

# 元组应用场景示例

# 1. 函数返回多个值
def get_name_age():
    """返回姓名和年龄"""
    return "张三", 25  # 实际返回的是元组

def calculate_stats(numbers):
    """计算统计信息"""
    return min(numbers), max(numbers), sum(numbers) / len(numbers)

name, age = get_name_age()
print(f"姓名: {name}, 年龄: {age}")

data = [1, 2, 3, 4, 5]
min_val, max_val, avg_val = calculate_stats(data)
print(f"最小值: {min_val}, 最大值: {max_val}, 平均值: {avg_val:.2f}")

# 2. 作为字典的键
student_grades = {
    ("张三", "数学"): 95,
    ("张三", "英语"): 87,
    ("李四", "数学"): 92,
    ("李四", "英语"): 89
}

print("张三的数学成绩:", student_grades[("张三", "数学")])

# 3. 数据的保护 - 配置信息
DATABASE_CONFIG = (
    "localhost",  # 主机
    5432,         # 端口
    "mydb",       # 数据库名
    "user",       # 用户名
    "password"    # 密码
)

host, port, db_name, username, password = DATABASE_CONFIG
print(f"数据库配置: {host}:{port}/{db_name}")

# 4. 坐标和点
points = [(0, 0), (1, 1), (2, 4), (3, 9)]
print("坐标点列表:", points)

# 计算距离
import math

def distance(point1, point2):
    """计算两点间距离"""
    x1, y1 = point1
    x2, y2 = point2
    return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)

dist = distance((0, 0), (3, 4))
print(f"两点间距离: {dist:.2f}")

输出结果:

姓名: 张三, 年龄: 25
最小值: 1, 最大值: 5, 平均值: 3.00
张三的数学成绩: 95
数据库配置: localhost:5432/mydb
坐标点列表: [(0, 0), (1, 1), (2, 4), (3, 9)]
两点间距离: 5.00

4.4 字典(Dictionary)

字典是Python中的映射类型,以键值对的形式存储数据,通过键来访问值。字典是无序的、可变的、不允许键重复的数据结构。

4.4.1 字典的基本操作

字典的定义与特点

字典具有以下特点:
- 无序:元素没有固定的位置(Python 3.7+保持插入顺序)
- 可变:可以修改、添加、删除键值对
- 键唯一:不允许重复的键
- 键必须可哈希:不可变类型如字符串、数字、元组(不包含可变对象)
- 值可以是任意类型:包括可变类型

# 字典的创建方法示例
# 花括号创建
student = {"name": "张三", "age": 20, "score": 95}
empty_dict = {}  # 空字典

# dict()构造函数
person = dict(name="李四", age=25, city="北京")
from_list = dict([("a", 1), ("b", 2), ("c", 3)])  # 从键值对列表创建

# 字典推导式
squares = {x: x**2 for x in range(5)}  # 创建平方数字典

print("学生信息:", student)
print("空字典:", empty_dict)
print("人员信息:", person)
print("从列表创建:", from_list)
print("平方数字典:", squares)
print("字典类型:", type(student))

输出结果:

学生信息: {'name': '张三', 'age': 20, 'score': 95}
空字典: {}
人员信息: {'name': '李四', 'age': 25, 'city': '北京'}
从列表创建: {'a': 1, 'b': 2, 'c': 3}
平方数字典: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
字典类型: <class 'dict'>
字典的访问与修改
# 字典访问与修改示例
student = {"name": "张三", "age": 20, "score": 95}
print("原始字典:", student)

# 键值访问
print("姓名:", student["name"])  # 通过键访问值

# get()方法 - 安全访问
print("年龄:", student.get("age"))  # 通过get方法访问值
print("地址:", student.get("address"))  # 键不存在返回None
print("地址:", student.get("address", "未知"))  # 提供默认值

# 添加和修改键值对
student["gender"] = "男"  # 添加新键值对
print("添加性别后:", student)

student["age"] = 21  # 修改已有键值对
print("修改年龄后:", student)

# 删除键值对
del student["score"]  # 使用del语句删除
print("删除成绩后:", student)

age = student.pop("age")  # 使用pop()方法删除并返回值
print(f"弹出的年龄: {age}")
print("弹出年龄后:", student)

last_item = student.popitem()  # 弹出最后添加的键值对
print(f"弹出的最后项: {last_item}")
print("弹出最后项后:", student)

# 清空字典
student.clear()
print("清空后:", student)

输出结果:

原始字典: {'name': '张三', 'age': 20, 'score': 95}
姓名: 张三
年龄: 20
地址: None
地址: 未知
添加性别后: {'name': '张三', 'age': 20, 'score': 95, 'gender': '男'}
修改年龄后: {'name': '张三', 'age': 21, 'score': 95, 'gender': '男'}
删除成绩后: {'name': '张三', 'age': 21, 'gender': '男'}
弹出的年龄: 21
弹出年龄后: {'name': '张三', 'gender': '男'}
弹出的最后项: ('gender', '男')
弹出最后项后: {'name': '张三'}
清空后: {}

4.4.2 字典的遍历

# 字典遍历示例
student = {
    "name": "张三",
    "age": 20,
    "gender": "男",
    "score": {"math": 95, "english": 88, "physics": 92}
}

# 遍历键
print("遍历键:")
for key in student.keys():
    print(f"  - {key}")

# 直接遍历字典(默认遍历键)
print("\n直接遍历字典:")
for key in student:
    print(f"  - {key}")

# 遍历值
print("\n遍历值:")
for value in student.values():
    print(f"  - {value}")

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

# 嵌套字典遍历
print("\n遍历嵌套字典:")
for subject, score in student["score"].items():
    print(f"  - {subject}: {score}")

# 字典遍历的最佳实践
print("\n带索引的遍历:")
for i, (key, value) in enumerate(student.items()):
    print(f"  {i+1}. {key}: {value}")

输出结果:

遍历键:
  - name
  - age
  - gender
  - score

直接遍历字典:
  - name
  - age
  - gender
  - score

遍历值:
  - 张三
  - 20
  - 男
  - {'math': 95, 'english': 88, 'physics': 92}

遍历键值对:
  - name: 张三
  - age: 20
  - gender: 男
  - score: {'math': 95, 'english': 88, 'physics': 92}

遍历嵌套字典:
  - math: 95
  - english: 88
  - physics: 92

带索引的遍历:
  1. name: 张三
  2. age: 20
  3. gender: 男
  4. score: {'math': 95, 'english': 88, 'physics': 92}

4.4.3 字典推导式

字典推导式是一种简洁创建字典的方式,类似于列表推导式。

# 字典推导式示例

# 基本语法
squares = {x: x**2 for x in range(6)}
print("平方数字典:", squares)

# 条件过滤
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
print("偶数平方字典:", even_squares)

# 从现有字典创建新字典
prices = {"apple": 5, "banana": 3, "orange": 4, "grape": 8}
discounted = {item: price * 0.8 for item, price in prices.items()}
print("原价格:", prices)
print("打折后价格:", discounted)

# 使用两个列表创建字典
fruits = ["apple", "banana", "orange"]
counts = [10, 15, 8]
fruit_inventory = {fruit: count for fruit, count in zip(fruits, counts)}
print("水果库存:", fruit_inventory)

# 键值交换
original = {"a": 1, "b": 2, "c": 3}
swapped = {value: key for key, value in original.items()}
print("原字典:", original)
print("键值交换后:", swapped)

# 嵌套字典推导式
matrix = {
    "A": [1, 2, 3],
    "B": [4, 5, 6],
    "C": [7, 8, 9]
}
flattened = {f"{key}{i+1}": value for key, values in matrix.items() for i, value in enumerate(values)}
print("嵌套列表字典:", matrix)
print("扁平化后:", flattened)

输出结果:

平方数字典: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
偶数平方字典: {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
原价格: {'apple': 5, 'banana': 3, 'orange': 4, 'grape': 8}
打折后价格: {'apple': 4.0, 'banana': 2.4, 'orange': 3.2, 'grape': 6.4}
水果库存: {'apple': 10, 'banana': 15, 'orange': 8}
原字典: {'a': 1, 'b': 2, 'c': 3}
键值交换后: {1: 'a', 2: 'b', 3: 'c'}
嵌套列表字典: {'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}
扁平化后: {'A1': 1, 'A2': 2, 'A3': 3, 'B1': 4, 'B2': 5, 'B3': 6, 'C1': 7, 'C2': 8, 'C3': 9}

4.5 集合(Set)

集合是Python中的无序可变数据结构,用于存储唯一的元素。集合中的元素不能重复,且必须是可哈希的(不可变类型)。

4.5.1 集合的基本操作

集合的定义与特点

集合具有以下特点:
- 无序:元素没有固定的位置或顺序
- 唯一:不允许重复元素
- 可变:可以添加或删除元素
- 元素必须可哈希:只能包含不可变类型(字符串、数字、元组等)
- 不支持索引和切片:因为是无序的

# 集合的创建方法示例
# 花括号创建
fruits = {"apple", "banana", "orange", "apple"}  # 重复元素会被自动去除
empty_set = set()  # 空集合(注意:{}创建的是空字典,不是空集合)

# set()构造函数
numbers = set([1, 2, 3, 2, 1])  # 从列表创建,自动去重
chars = set("hello")  # 从字符串创建,每个字符作为一个元素

# 集合推导式
squares = {x**2 for x in range(10) if x % 2 == 0}  # 创建偶数的平方集合

print("水果集合:", fruits)
print("空集合:", empty_set)
print("数字集合:", numbers)
print("字符集合:", chars)  # 注意顺序是无法预测的
print("平方集合:", squares)
print("集合类型:", type(fruits))

输出结果:

水果集合: {'orange', 'apple', 'banana'}
空集合: set()
数字集合: {1, 2, 3}
字符集合: {'e', 'o', 'h', 'l'}
平方集合: {0, 4, 16, 36, 64}
集合类型: <class 'set'>
集合的基本操作
# 集合基本操作示例
fruits = {"apple", "banana", "orange"}
print("原始集合:", fruits)

# 添加元素
fruits.add("grape")  # 添加单个元素
print("添加grape后:", fruits)

fruits.update(["pear", "melon"])  # 添加多个元素
print("更新后:", fruits)

# 删除元素
fruits.remove("banana")  # 删除指定元素,如果元素不存在会引发KeyError
print("删除banana后:", fruits)

fruits.discard("kiwi")  # 删除指定元素,如果元素不存在不会引发错误
print("尝试删除不存在元素后:", fruits)

popped = fruits.pop()  # 随机移除一个元素并返回
print(f"弹出的元素: {popped}")
print("弹出元素后:", fruits)

fruits.clear()  # 清空集合
print("清空后:", fruits)

# 成员检测
vegetables = {"carrot", "potato", "tomato"}
print("\n蔬菜集合:", vegetables)
print("'potato'在集合中:", "potato" in vegetables)
print("'apple'不在集合中:", "apple" not in vegetables)

输出结果:

原始集合: {'orange', 'apple', 'banana'}
添加grape后: {'orange', 'apple', 'banana', 'grape'}
更新后: {'pear', 'orange', 'melon', 'apple', 'banana', 'grape'}
删除banana后: {'pear', 'orange', 'melon', 'apple', 'grape'}
尝试删除不存在元素后: {'pear', 'orange', 'melon', 'apple', 'grape'}
弹出的元素: pear
弹出元素后: {'orange', 'melon', 'apple', 'grape'}
清空后: set()

蔬菜集合: {'tomato', 'potato', 'carrot'}
'potato'在集合中: True
'apple'不在集合中: True

4.5.2 集合的数学操作

集合类型实现了数学中集合的概念,支持并集、交集、差集等操作。

# 集合数学操作示例
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
print("集合A:", A)
print("集合B:", B)

# 并集(两个集合中的所有元素)
union1 = A.union(B)  # 使用union()方法
union2 = A | B       # 使用|运算符
print("并集 (A ∪ B):", union1)
print("并集 (A | B):", union2)

# 交集(两个集合共有的元素)
intersection1 = A.intersection(B)  # 使用intersection()方法
intersection2 = A & B              # 使用&运算符
print("交集 (A ∩ B):", intersection1)
print("交集 (A & B):", intersection2)

# 差集(在A中但不在B中的元素)
difference1 = A.difference(B)  # 使用difference()方法
difference2 = A - B            # 使用-运算符
print("差集 (A - B):", difference1)
print("差集 (A - B):", difference2)

# 对称差集(在A或B中,但不同时在两者中的元素)
sym_diff1 = A.symmetric_difference(B)  # 使用symmetric_difference()方法
sym_diff2 = A ^ B                      # 使用^运算符
print("对称差集 (A △ B):", sym_diff1)
print("对称差集 (A ^ B):", sym_diff2)

# 子集与超集
C = {1, 2}
D = {1, 2, 3, 4, 5, 6}
print("\n集合C:", C)
print("集合D:", D)

# 检查子集
print("C是A的子集:", C.issubset(A))
print("C是A的子集:", C <= A)
print("C是A的真子集:", C < A)  # 真子集意味着C是A的子集且C不等于A

# 检查超集
print("D是B的超集:", D.issuperset(B))
print("D是B的超集:", D >= B)
print("D是B的真超集:", D > B)  # 真超集意味着D是B的超集且D不等于B

# 检查两个集合是否没有共同元素
E = {1, 2, 3}
F = {4, 5, 6}
print("\n集合E:", E)
print("集合F:", F)
print("E和F是否不相交:", E.isdisjoint(F))  # 如果没有共同元素,返回True

输出结果:

集合A: {1, 2, 3, 4, 5}
集合B: {4, 5, 6, 7, 8}
并集 (A ∪ B): {1, 2, 3, 4, 5, 6, 7, 8}
并集 (A | B): {1, 2, 3, 4, 5, 6, 7, 8}
交集 (A ∩ B): {4, 5}
交集 (A & B): {4, 5}
差集 (A - B): {1, 2, 3}
差集 (A - B): {1, 2, 3}
对称差集 (A △ B): {1, 2, 3, 6, 7, 8}
对称差集 (A ^ B): {1, 2, 3, 6, 7, 8}

集合C: {1, 2}
集合D: {1, 2, 3, 4, 5, 6}
C是A的子集: True
C是A的子集: True
C是A的真子集: True
D是B的超集: True
D是B的超集: True
D是B的真超集: True

集合E: {1, 2, 3}
集合F: {4, 5, 6}
E和F是否不相交: True
集合的实际应用
# 集合的实际应用示例

# 1. 去除列表中的重复元素
duplicates = [1, 2, 3, 1, 2, 5, 6, 7, 8, 8, 1]
unique_list = list(set(duplicates))
print("原列表:", duplicates)
print("去重后:", unique_list)

# 2. 查找共同元素
users_a = {"Alice", "Bob", "Charlie", "David"}
users_b = {"Charlie", "Eve", "Frank", "David"}
common_users = users_a & users_b
print("\n用户组A:", users_a)
print("用户组B:", users_b)
print("共同用户:", common_users)

# 3. 查找唯一元素
only_in_a = users_a - users_b
only_in_b = users_b - users_a
print("只在A中的用户:", only_in_a)
print("只在B中的用户:", only_in_b)

# 4. 检查两个字符串是否使用相同字符
str1 = "listen"
str2 = "silent"
print(f"\n{str1}{str2}使用相同字符集:", set(str1) == set(str2))

# 5. 统计文本中的唯一单词数
text = "to be or not to be that is the question"
unique_words = set(text.split())
print("\n文本:", text)
print("唯一单词数:", len(unique_words))
print("唯一单词:", unique_words)

输出结果:

原列表: [1, 2, 3, 1, 2, 5, 6, 7, 8, 8, 1]
去重后: [1, 2, 3, 5, 6, 7, 8]

用户组A: {'Charlie', 'Alice', 'David', 'Bob'}
用户组B: {'Charlie', 'Eve', 'David', 'Frank'}
共同用户: {'Charlie', 'David'}
只在A中的用户: {'Alice', 'Bob'}
只在B中的用户: {'Eve', 'Frank'}

listen和silent使用相同字符集: True

文本: to be or not to be that is the question
唯一单词数: 8
唯一单词: {'that', 'not', 'question', 'or', 'the', 'is', 'to', 'be'}

4.6 数据结构的选择与应用

在Python编程中,选择合适的数据结构对于程序的效率和可读性至关重要。本节将对前面介绍的数据结构进行对比,并提供选择指南。

4.6.1 各种数据结构的特点对比

下面是Python主要数据结构的特点对比:

# 数据结构特点对比示例
import sys

# 创建各种数据结构并比较
test_str = "Python"
test_list = ["P", "y", "t", "h", "o", "n"]
test_tuple = ("P", "y", "t", "h", "o", "n")
test_dict = {"P": 1, "y": 2, "t": 3, "h": 4, "o": 5, "n": 6}
test_set = {"P", "y", "t", "h", "o", "n"}

# 比较内存占用
print("内存占用比较:")
print(f"字符串: {sys.getsizeof(test_str)} 字节")
print(f"列表: {sys.getsizeof(test_list)} 字节")
print(f"元组: {sys.getsizeof(test_tuple)} 字节")
print(f"字典: {sys.getsizeof(test_dict)} 字节")
print(f"集合: {sys.getsizeof(test_set)} 字节")

# 特性对比表格
print("\n数据结构特性对比:")
print("-" * 70)
print(f"{'特性':<15}{'字符串':<12}{'列表':<12}{'元组':<12}{'字典':<12}{'集合':<12}")
print("-" * 70)
print(f"{'可变性':<15}{'不可变':<12}{'可变':<12}{'不可变':<12}{'可变':<12}{'可变':<12}")
print(f"{'有序性':<15}{'有序':<12}{'有序':<12}{'有序':<12}{'有序*':<12}{'无序':<12}")
print(f"{'索引访问':<15}{'支持':<12}{'支持':<12}{'支持':<12}{'键访问':<12}{'不支持':<12}")
print(f"{'重复元素':<15}{'允许':<12}{'允许':<12}{'允许':<12}{'键唯一':<12}{'不允许':<12}")
print(f"{'异构元素':<15}{'字符':<12}{'任意类型':<12}{'任意类型':<12}{'键值对':<12}{'可哈希类型':<12}")
print("-" * 70)
print("* Python 3.7+中字典保持插入顺序")

输出结果:

内存占用比较:
字符串: 55 字节
列表: 120 字节
元组: 88 字节
字典: 232 字节
集合: 216 字节

数据结构特性对比:
----------------------------------------------------------------------
特性            字符串        列表        元组        字典        集合        
----------------------------------------------------------------------
可变性          不可变      可变        不可变      可变        可变        
有序性          有序        有序        有序        有序*       无序        
索引访问        支持        支持        支持        键访问      不支持      
重复元素        允许        允许        允许        键唯一      不允许      
异构元素        字符        任意类型    任意类型    键值对      可哈希类型  
----------------------------------------------------------------------
* Python 3.7+中字典保持插入顺序

4.6.2 不同场景下的数据结构选择

# 不同场景的数据结构选择示例

# 1. 需要有序数据时
print("有序数据场景:")

# 使用列表存储学生成绩并保持顺序
scores = [85, 92, 78, 90, 88]
print(f"原始成绩: {scores}")
scores.sort()
print(f"排序后成绩: {scores}")

# 使用元组存储不可变的坐标点
point = (10, 20)
print(f"坐标点: {point}")

# 2. 需要快速查找时
print("\n快速查找场景:")

# 使用字典存储学生信息,通过学号快速查找
students = {
    "1001": {"name": "张三", "age": 20, "major": "计算机科学"},
    "1002": {"name": "李四", "age": 21, "major": "数学"},
    "1003": {"name": "王五", "age": 22, "major": "物理"}
}
print(f"查找学号1002的学生: {students['1002']['name']}")

# 使用集合进行快速成员检测
allowed_users = {"admin", "manager", "editor"}
user = "editor"
print(f"用户'{user}'是否有权限: {user in allowed_users}")

# 3. 需要唯一元素时
print("\n唯一元素场景:")

# 使用集合去除重复元素
visitor_ips = ["192.168.1.1", "192.168.1.2", "192.168.1.1", 
               "192.168.1.3", "192.168.1.2", "192.168.1.4"]
unique_ips = set(visitor_ips)
print(f"原始IP列表: {visitor_ips}")
print(f"唯一IP数量: {len(unique_ips)}")
print(f"唯一IP列表: {unique_ips}")

# 4. 需要键值对映射时
print("\n键值对映射场景:")

# 使用字典存储配置信息
config = {
    "host": "localhost",
    "port": 8080,
    "debug": True,
    "max_connections": 100
}
print(f"服务器配置: {config}")
print(f"服务器端口: {config['port']}")

# 使用字典计数
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
word_count = {}
for word in words:
    if word in word_count:
        word_count[word] += 1
    else:
        word_count[word] = 1
print(f"单词列表: {words}")
print(f"单词计数: {word_count}")

输出结果:

有序数据场景:
原始成绩: [85, 92, 78, 90, 88]
排序后成绩: [78, 85, 88, 90, 92]
坐标点: (10, 20)

快速查找场景:
查找学号1002的学生: 李四
用户'editor'是否有权限: True

唯一元素场景:
原始IP列表: ['192.168.1.1', '192.168.1.2', '192.168.1.1', '192.168.1.3', '192.168.1.2', '192.168.1.4']
唯一IP数量: 4
唯一IP列表: {'192.168.1.2', '192.168.1.3', '192.168.1.1', '192.168.1.4'}

键值对映射场景:
服务器配置: {'host': 'localhost', 'port': 8080, 'debug': True, 'max_connections': 100}
服务器端口: 8080
单词列表: ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
单词计数: {'apple': 3, 'banana': 2, 'orange': 1}

4.6.3 性能考量

在选择数据结构时,需要考虑操作的时间复杂度和空间复杂度。

# 性能考量示例
import time
import random

# 准备测试数据
small_list = list(range(1000))
random.shuffle(small_list)
small_set = set(small_list)
small_dict = {i: i for i in small_list}

# 测试查找性能
print("查找性能测试:")

# 列表查找
start = time.time()
for _ in range(1000):
    500 in small_list
list_time = time.time() - start
print(f"列表查找耗时: {list_time:.6f}秒")

# 集合查找
start = time.time()
for _ in range(1000):
    500 in small_set
set_time = time.time() - start
print(f"集合查找耗时: {set_time:.6f}秒")

# 字典查找
start = time.time()
for _ in range(1000):
    500 in small_dict
dict_time = time.time() - start
print(f"字典查找耗时: {dict_time:.6f}秒")

print(f"集合比列表快: {list_time/set_time:.1f}倍")
print(f"字典比列表快: {list_time/dict_time:.1f}倍")

# 常见操作的时间复杂度
print("\n常见操作的时间复杂度:")
print("-" * 70)
print(f"{'操作':<20}{'列表':<15}{'元组':<15}{'字典':<15}{'集合':<15}")
print("-" * 70)
print(f"{'访问元素':<20}{'O(1)':<15}{'O(1)':<15}{'O(1)':<15}{'N/A':<15}")
print(f"{'搜索元素':<20}{'O(n)':<15}{'O(n)':<15}{'O(1)':<15}{'O(1)':<15}")
print(f"{'插入元素':<20}{'O(1)/O(n)*':<15}{'N/A':<15}{'O(1)':<15}{'O(1)':<15}")
print(f"{'删除元素':<20}{'O(1)/O(n)*':<15}{'N/A':<15}{'O(1)':<15}{'O(1)':<15}")
print("-" * 70)
print("* 列表在末尾操作是O(1),在开头或中间操作是O(n)")

输出结果(实际运行时间可能有所不同):

查找性能测试:
列表查找耗时: 0.023438秒
集合查找耗时: 0.000998秒
字典查找耗时: 0.000999秒
集合比列表快: 23.5倍
字典比列表快: 23.5倍

常见操作的时间复杂度:
----------------------------------------------------------------------
操作                  列表            元组            字典            集合            
----------------------------------------------------------------------
访问元素              O(1)            O(1)            O(1)            N/A             
搜索元素              O(n)            O(n)            O(1)            O(1)            
插入元素              O(1)/O(n)*      N/A             O(1)            O(1)            
删除元素              O(1)/O(n)*      N/A             O(1)            O(1)            
----------------------------------------------------------------------
* 列表在末尾操作是O(1),在开头或中间操作是O(n)

4.6.4 实际应用案例

# 实际应用案例示例

# 案例1: 数据分析 - 统计文本中单词频率
def word_frequency_analysis(text):
    """分析文本中单词出现的频率"""
    # 将文本转换为小写并分割成单词
    words = text.lower().split()

    # 使用字典统计频率
    frequency = {}
    for word in words:
        # 去除标点符号
        word = word.strip('.,!?;:()"\'')
        if word:
            frequency[word] = frequency.get(word, 0) + 1

    # 按频率排序
    sorted_freq = sorted(frequency.items(), key=lambda x: x[1], reverse=True)
    return sorted_freq

# 示例文本
sample_text = """Python is a programming language that lets you work quickly and integrate systems more effectively. 
               Python is powerful and fast, plays well with others, runs everywhere, is friendly and easy to learn."""

print("案例1: 文本单词频率分析")
word_freq = word_frequency_analysis(sample_text)
print("前5个高频单词:")
for word, count in word_freq[:5]:
    print(f"  {word}: {count}次")

# 案例2: 数据去重与合并 - 合并用户数据
def merge_user_data(user_lists):
    """合并多个用户列表并去除重复"""
    # 使用集合去重
    all_users = set()
    for user_list in user_lists:
        all_users.update(user_list)

    # 转回列表并排序
    return sorted(list(all_users))

# 示例用户数据
users_site_a = ["user1", "user2", "user3", "user4"]
users_site_b = ["user2", "user3", "user5", "user6"]
users_site_c = ["user1", "user6", "user7"]

print("\n案例2: 用户数据合并与去重")
merged_users = merge_user_data([users_site_a, users_site_b, users_site_c])
print(f"站点A用户: {users_site_a}")
print(f"站点B用户: {users_site_b}")
print(f"站点C用户: {users_site_c}")
print(f"合并后的唯一用户: {merged_users}")
print(f"唯一用户总数: {len(merged_users)}")

# 案例3: 数据结构组合 - 简单购物车系统
class ShoppingCart:
    """简单购物车系统"""
    def __init__(self):
        # 使用字典存储商品及数量
        self.items = {}

    def add_item(self, item_id, name, price, quantity=1):
        """添加商品到购物车"""
        if item_id in self.items:
            # 更新现有商品数量
            self.items[item_id]["quantity"] += quantity
        else:
            # 添加新商品
            self.items[item_id] = {
                "name": name,
                "price": price,
                "quantity": quantity
            }

    def remove_item(self, item_id, quantity=None):
        """从购物车移除商品"""
        if item_id not in self.items:
            return False

        if quantity is None or quantity >= self.items[item_id]["quantity"]:
            # 完全移除商品
            del self.items[item_id]
        else:
            # 减少商品数量
            self.items[item_id]["quantity"] -= quantity
        return True

    def get_total(self):
        """计算购物车总价"""
        return sum(item["price"] * item["quantity"] for item in self.items.values())

    def get_item_count(self):
        """获取购物车中商品总数"""
        return sum(item["quantity"] for item in self.items.values())

    def __str__(self):
        """购物车字符串表示"""
        if not self.items:
            return "购物车为空"

        cart_str = "购物车内容:\n"
        cart_str += "-" * 50 + "\n"
        cart_str += f"{'商品名称':<20}{'单价':<10}{'数量':<10}{'小计':<10}\n"
        cart_str += "-" * 50 + "\n"

        for item in self.items.values():
            subtotal = item["price"] * item["quantity"]
            cart_str += f"{item['name']:<20}{item['price']:<10}{item['quantity']:<10}{subtotal:<10.2f}\n"

        cart_str += "-" * 50 + "\n"
        cart_str += f"总计: {self.get_total():.2f} 元 ({self.get_item_count()} 件商品)"
        return cart_str

print("\n案例3: 购物车系统")
cart = ShoppingCart()
cart.add_item("p001", "Python编程入门", 79.0, 1)
cart.add_item("p002", "数据结构与算法", 85.5, 2)
cart.add_item("p003", "Web开发实战", 95.0, 1)

print(cart)
print("\n移除一本'数据结构与算法'...")
cart.remove_item("p002", 1)
print(cart)

输出结果:

案例1: 文本单词频率分析
前5个高频单词:
  and: 4次
  is: 3次
  python: 2次
  to: 2次
  you: 1次

案例2: 用户数据合并与去重
站点A用户: ['user1', 'user2', 'user3', 'user4']
站点B用户: ['user2', 'user3', 'user5', 'user6']
站点C用户: ['user1', 'user6', 'user7']
合并后的唯一用户: ['user1', 'user2', 'user3', 'user4', 'user5', 'user6', 'user7']
唯一用户总数: 7

案例3: 购物车系统
购物车内容:
--------------------------------------------------
商品名称                单价      数量      小计      
--------------------------------------------------
Python编程入门          79.0      1         79.0      
数据结构与算法          85.5      2         171.0     
Web开发实战             95.0      1         95.0      
--------------------------------------------------
总计: 345.00 元 (4 件商品)

移除一本'数据结构与算法'...
购物车内容:
--------------------------------------------------
商品名称                单价      数量      小计      
--------------------------------------------------
Python编程入门          79.0      1         79.0      
数据结构与算法          85.5      1         85.5      
Web开发实战             95.0      1         95.0      
--------------------------------------------------
总计: 259.50 元 (3 件商品)

总结

本章详细介绍了Python中的五种主要数据结构:字符串、列表、元组、字典和集合。每种数据结构都有其独特的特点和适用场景:

  1. 字符串:适用于文本处理,提供了丰富的字符串操作方法。
  2. 列表:适用于存储有序、可变的元素序列,支持各种操作和修改。
  3. 元组:适用于存储不可变的有序元素序列,可作为字典键或确保数据不被修改。
  4. 字典:适用于键值对映射,提供高效的查找和存储。
  5. 集合:适用于存储唯一元素,支持集合运算,高效的成员检测。

选择合适的数据结构应考虑:
- 数据的性质(有序/无序、可变/不可变)
- 需要执行的操作(访问、搜索、插入、删除)
- 性能要求(时间和空间复杂度)
- 代码可读性和维护性

掌握这些数据结构及其适用场景,将帮助你编写更高效、更优雅的Python代码。

小夜