Python 容器数据类型
目录
- [列表 list](#列表 list "#%E5%88%97%E8%A1%A8-list")
- [元组 tuple](#元组 tuple "#%E5%85%83%E7%BB%84-tuple")
- [字典 dict](#字典 dict "#%E5%AD%97%E5%85%B8-dict")
- [集合 set](#集合 set "#%E9%9B%86%E5%90%88-set")
- [字符串 str](#字符串 str "#%E5%AD%97%E7%AC%A6%E4%B8%B2-str")
- 容器操作通用方法
- 综合实战
列表 list
列表是 Python 中最常用的可变有序序列。
创建列表
python
# 空列表
empty_list = []
empty_list = list()
# 初始化列表
fruits = ["苹果", "香蕉", "橙子"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True, [1, 2]]
# 使用 list() 转换
string_list = list("hello") # ['h', 'e', 'l', 'l', 'o']
range_list = list(range(5)) # [0, 1, 2, 3, 4]
访问元素
python
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
# 正向索引(从 0 开始)
print(fruits[0]) # 苹果
print(fruits[2]) # 橙子
# 负向索引(从 -1 开始)
print(fruits[-1]) # 西瓜
print(fruits[-2]) # 葡萄
# 切片 [start:stop:step]
print(fruits[1:3]) # ['香蕉', '橙子']
print(fruits[:3]) # ['苹果', '香蕉', '橙子']
print(fruits[2:]) # ['橙子', '葡萄', '西瓜']
print(fruits[::2]) # ['苹果', '橙子', '西瓜']
print(fruits[::-1]) # ['西瓜', '葡萄', '橙子', '香蕉', '苹果'](反转)
修改列表
python
fruits = ["苹果", "香蕉", "橙子"]
# 修改元素
fruits[1] = "芒果"
print(fruits) # ['苹果', '芒果', '橙子']
# 添加元素
fruits.append("葡萄") # 末尾添加
fruits.insert(1, "草莓") # 指定位置插入
fruits.extend(["西瓜", "哈密瓜"]) # 扩展列表
print(fruits) # ['苹果', '草莓', '芒果', '橙子', '葡萄', '西瓜', '哈密瓜']
# 删除元素
fruits.remove("芒果") # 删除指定值
del fruits[0] # 删除指定索引
popped = fruits.pop() # 删除并返回最后一个元素
popped = fruits.pop(1) # 删除并返回指定索引的元素
print(fruits)
print(f"弹出: {popped}")
列表常用方法
python
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
# 查询
print(len(numbers)) # 9(长度)
print(numbers.count(5)) # 2(出现次数)
print(numbers.index(4)) # 2(首次出现的索引)
# 排序
numbers.sort() # 原地排序
print(numbers) # [1, 1, 2, 3, 4, 5, 5, 6, 9]
numbers.sort(reverse=True) # 降序
print(numbers) # [9, 6, 5, 5, 4, 3, 2, 1, 1]
# 反转
numbers.reverse()
print(numbers)
# 复制
copy1 = numbers.copy()
copy2 = numbers[:]
copy3 = list(numbers)
列表推导式
python
# 基本推导式
squares = [x ** 2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# 带条件
even_squares = [x ** 2 for x in range(1, 11) if x % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100]
# 嵌套推导式
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]]
# 扁平化二维列表
flat = [num for row in matrix for num in row]
print(flat) # [1, 2, 3, 2, 4, 6, 3, 6, 9]
列表运算
python
# 拼接
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = list1 + list2
print(list3) # [1, 2, 3, 4, 5, 6]
# 重复
zeros = [0] * 5
print(zeros) # [0, 0, 0, 0, 0]
# 成员检查
print(3 in list1) # True
print(10 not in list1) # True
元组 tuple
元组是不可变的有序序列,适合存储固定数据。
创建元组
python
# 空元组
empty_tuple = ()
empty_tuple = tuple()
# 单元素元组(注意逗号)
single = (42,)
single = 42,
# 多元素元组
coordinates = (10, 20)
person = ("张三", 25, "北京")
# 省略括号
point = 10, 20, 30
# 使用 tuple() 转换
tuple_from_list = tuple([1, 2, 3])
tuple_from_string = tuple("abc") # ('a', 'b', 'c')
访问元素
python
colors = ("红", "绿", "蓝", "黄")
# 索引访问
print(colors[0]) # 红
print(colors[-1]) # 黄
# 切片
print(colors[1:3]) # ('绿', '蓝')
# ❌ 不能修改
# colors[0] = "紫" # TypeError
元组解包
python
# 基本解包
point = (10, 20)
x, y = point
print(f"x={x}, y={y}")
# 交换变量
a, b = 1, 2
a, b = b, a
print(f"a={a}, b={b}") # a=2, b=1
# 星号解包
numbers = (1, 2, 3, 4, 5)
first, *middle, last = numbers
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
# 函数返回多个值
def get_user():
return "李四", 30, "上海"
name, age, city = get_user()
元组方法
python
numbers = (1, 2, 3, 2, 4, 2, 5)
print(numbers.count(2)) # 3(出现次数)
print(numbers.index(3)) # 2(首次出现的索引)
print(len(numbers)) # 7(长度)
元组 vs 列表
| 特性 | 列表 | 元组 |
|---|---|---|
| 可变性 | 可变 | 不可变 |
| 性能 | 较慢 | 较快 |
| 内存占用 | 较大 | 较小 |
| 可作字典键 | ❌ | ✅ |
| 适用场景 | 动态数据 | 固定数据 |
python
# 元组可以作为字典的键
locations = {
(40.7128, -74.0060): "纽约",
(51.5074, -0.1278): "伦敦",
}
# 元组用于保护数据不被修改
def get_constants():
return (3.14159, 2.71828, 1.41421)
PI, E, SQRT2 = get_constants()
字典 dict
字典是键值对的无序集合(Python 3.7+ 保持插入顺序)。
创建字典
python
# 空字典
empty_dict = {}
empty_dict = dict()
# 字面量创建
student = {
"name": "王五",
"age": 20,
"major": "计算机科学",
"scores": [90, 85, 92]
}
# dict() 构造函数
dict1 = dict(name="张三", age=25)
dict2 = dict([("a", 1), ("b", 2)])
dict3 = dict.fromkeys(["x", "y", "z"], 0) # {'x': 0, 'y': 0, 'z': 0}
# 字典推导式
squares = {x: x**2 for x in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
访问元素
python
student = {"name": "张三", "age": 20, "city": "北京"}
# 通过键访问
print(student["name"]) # 张三
print(student.get("age")) # 20
print(student.get("score")) # None(键不存在)
print(student.get("score", 0)) # 0(提供默认值)
# ❌ 访问不存在的键会报错
# print(student["score"]) # KeyError
修改字典
python
student = {"name": "张三", "age": 20}
# 添加/修改键值对
student["age"] = 21 # 修改
student["city"] = "上海" # 添加
student.update({"major": "CS", "grade": "大二"}) # 批量更新
print(student)
# {'name': '张三', 'age': 21, 'city': '上海', 'major': 'CS', 'grade': '大二'}
# 删除
del student["city"] # 删除指定键
age = student.pop("age") # 删除并返回值
last_item = student.popitem() # 删除并返回最后一项(LIFO)
student.clear() # 清空字典
遍历字典
python
student = {"name": "李四", "age": 22, "city": "广州"}
# 遍历键
for key in student:
print(key)
# 遍历键和值
for key, value in student.items():
print(f"{key}: {value}")
# 只遍历值
for value in student.values():
print(value)
# 遍历键(显式)
for key in student.keys():
print(key)
字典方法
python
d = {"a": 1, "b": 2, "c": 3}
# 获取所有键、值、项
print(list(d.keys())) # ['a', 'b', 'c']
print(list(d.values())) # [1, 2, 3]
print(list(d.items())) # [('a', 1), ('b', 2), ('c', 3)]
# 检查键是否存在
print("a" in d) # True
print("x" not in d) # True
# 设置默认值
d.setdefault("d", 4) # 如果键不存在则添加
print(d) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# 合并字典(Python 3.9+)
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
d3 = d1 | d2 # {'a': 1, 'b': 3, 'c': 4}
d1 |= d2 # 原地更新
嵌套字典
python
school = {
"class_1": {
"teacher": "张老师",
"students": [
{"name": "小明", "score": 90},
{"name": "小红", "score": 95}
]
},
"class_2": {
"teacher": "李老师",
"students": [
{"name": "小刚", "score": 88},
{"name": "小丽", "score": 92}
]
}
}
# 访问嵌套数据
print(school["class_1"]["teacher"]) # 张老师
print(school["class_1"]["students"][0]["name"]) # 小明
# 遍历
for class_name, info in school.items():
print(f"\n{class_name}:")
print(f" 班主任: {info['teacher']}")
print(f" 学生数: {len(info['students'])}")
for student in info["students"]:
print(f" - {student['name']}: {student['score']}分")
defaultdict 和 OrderedDict
python
from collections import defaultdict, OrderedDict
# defaultdict - 自动初始化默认值
word_count = defaultdict(int)
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
for word in words:
word_count[word] += 1
print(dict(word_count)) # {'apple': 3, 'banana': 2, 'orange': 1}
# OrderedDict - 记住插入顺序(Python 3.7+ 普通字典也有序)
ordered = OrderedDict()
ordered["first"] = 1
ordered["second"] = 2
ordered["third"] = 3
集合 set
集合是无序的不重复元素集合。
创建集合
python
# 空集合(注意:{} 是空字典)
empty_set = set()
# 初始化集合
fruits = {"苹果", "香蕉", "橙子"}
numbers = {1, 2, 3, 4, 5}
# 使用 set() 转换
set_from_list = set([1, 2, 2, 3, 3, 3]) # {1, 2, 3}(去重)
set_from_string = set("hello") # {'h', 'e', 'l', 'o'}
# 集合推导式
squares = {x**2 for x in range(-5, 6)}
print(squares) # {0, 1, 4, 9, 16, 25}
集合操作
python
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
# 并集
print(A | B) # {1, 2, 3, 4, 5, 6, 7, 8}
print(A.union(B))
# 交集
print(A & B) # {4, 5}
print(A.intersection(B))
# 差集
print(A - B) # {1, 2, 3}
print(A.difference(B))
# 对称差集(只在其中一个集合中的元素)
print(A ^ B) # {1, 2, 3, 6, 7, 8}
print(A.symmetric_difference(B))
集合方法
python
fruits = {"苹果", "香蕉", "橙子"}
# 添加元素
fruits.add("葡萄")
fruits.update(["西瓜", "哈密瓜"])
# 删除元素
fruits.remove("香蕉") # 不存在会报错
fruits.discard("芒果") # 不存在不会报错
popped = fruits.pop() # 随机删除并返回一个元素
# 集合运算
A = {1, 2, 3}
B = {2, 3, 4}
print(A.issubset(B)) # False(A 是否是 B 的子集)
print(A.issuperset(B)) # False(A 是否是 B 的超集)
print(A.isdisjoint(B)) # False(是否有交集)
集合应用
python
# 去重
numbers = [1, 2, 2, 3, 3, 3, 4, 5]
unique = list(set(numbers))
print(unique) # [1, 2, 3, 4, 5]
# 查找共同元素
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = set(list1) & set(list2)
print(common) # {4, 5}
# 检查成员(比列表快)
valid_ids = {1001, 1002, 1003, 1004, 1005}
user_id = 1003
if user_id in valid_ids: # O(1) 时间复杂度
print("有效用户")
frozenset(不可变集合)
python
# 不可变集合,可作为字典的键或集合的元素
frozen = frozenset([1, 2, 3])
# frozen.add(4) # AttributeError
# 作为字典的键
data = {
frozenset([1, 2]): "第一组",
frozenset([3, 4]): "第二组"
}
字符串 str
字符串是不可变的字符序列。
创建字符串
python
# 单引号或双引号
str1 = 'Hello'
str2 = "World"
# 三引号(多行字符串)
multiline = """这是
多行
字符串"""
# 原始字符串(不转义)
path = r"C:\Users\name\file.txt"
regex = r"\d+\.\d+"
# 格式化字符串
name = "张三"
age = 25
greeting = f"你好,我叫{name},今年{age}岁"
字符串操作
python
text = "Hello, World!"
# 长度
print(len(text)) # 13
# 索引和切片
print(text[0]) # H
print(text[-1]) # !
print(text[7:12]) # World
# ❌ 不能修改
# text[0] = 'h' # TypeError
常用方法
python
text = " Hello, World! "
# 大小写转换
print(text.upper()) # " HELLO, WORLD! "
print(text.lower()) # " hello, world! "
print(text.title()) # " Hello, World! "
print(text.swapcase()) # " hELLO, wORLD! "
# 去除空白
print(text.strip()) # "Hello, World!"
print(text.lstrip()) # "Hello, World! "
print(text.rstrip()) # " Hello, World!"
# 查找和替换
print(text.find("World")) # 9(找不到返回 -1)
print(text.index("World")) # 9(找不到抛出异常)
print(text.replace("World", "Python"))
print(text.count("l")) # 3
# 判断
print("hello".isalpha()) # True(纯字母)
print("123".isdigit()) # True(纯数字)
print("hello123".isalnum()) # True(字母或数字)
print(" ".isspace()) # True(空白)
print("Hello".startswith("He")) # True
print("Hello".endswith("lo")) # True
分割和连接
python
text = "apple,banana,orange"
# 分割
fruits = text.split(",")
print(fruits) # ['apple', 'banana', 'orange']
text2 = "one two three"
words = text2.split() # 默认按空白分割
print(words) # ['one', 'two', 'three']
# 连接
result = "-".join(fruits)
print(result) # "apple-banana-orange"
# 分区
path = "/usr/local/bin/python"
parts = path.rsplit("/", 1)
print(parts) # ['/usr/local/bin', 'python']
字符串格式化
python
name = "李四"
age = 30
score = 95.5
# f-string(推荐)
print(f"姓名: {name}, 年龄: {age}, 分数: {score:.1f}")
# format()
print("姓名: {}, 年龄: {}".format(name, age))
print("姓名: {n}, 年龄: {a}".format(n=name, a=age))
# % 格式化
print("姓名: %s, 年龄: %d" % (name, age))
字符串编码
python
# UTF-8 编码
text = "你好世界"
encoded = text.encode("utf-8")
print(encoded) # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c'
decoded = encoded.decode("utf-8")
print(decoded) # 你好世界
容器操作通用方法
长度、最大最小值
python
# 适用于列表、元组、字典、集合、字符串
lst = [3, 1, 4, 1, 5, 9]
tpl = (3, 1, 4, 1, 5, 9)
dct = {"a": 1, "b": 2, "c": 3}
st = {3, 1, 4, 1, 5, 9}
s = "hello"
print(len(lst)) # 6
print(len(tpl)) # 6
print(len(dct)) # 3
print(len(st)) # 5(去重后)
print(len(s)) # 5
print(max(lst)) # 9
print(min(lst)) # 1
print(sum(lst)) # 23
排序
python
# sorted() - 返回新列表,不修改原对象
numbers = [3, 1, 4, 1, 5, 9]
sorted_nums = sorted(numbers)
print(sorted_nums) # [1, 1, 3, 4, 5, 9]
print(numbers) # [3, 1, 4, 1, 5, 9](未改变)
# 自定义排序
students = [
{"name": "张三", "score": 85},
{"name": "李四", "score": 92},
{"name": "王五", "score": 78}
]
# 按分数排序
sorted_students = sorted(students, key=lambda s: s["score"])
for s in sorted_students:
print(f"{s['name']}: {s['score']}")
# 降序
sorted_desc = sorted(students, key=lambda s: s["score"], reverse=True)
枚举和压缩
python
# enumerate - 获取索引和值
fruits = ["苹果", "香蕉", "橙子"]
for index, fruit in enumerate(fruits, start=1):
print(f"{index}. {fruit}")
# zip - 并行迭代
names = ["张三", "李四", "王五"]
ages = [20, 25, 30]
for name, age in zip(names, ages):
print(f"{name}: {age}岁")
映射和过滤
python
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# map - 映射
squares = list(map(lambda x: x**2, numbers))
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# filter - 过滤
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# 推荐使用列表推导式替代
squares = [x**2 for x in numbers]
evens = [x for x in numbers if x % 2 == 0]
any 和 all
python
# any - 至少一个为 True
print(any([False, False, True])) # True
print(any([False, False, False])) # False
# all - 全部为 True
print(all([True, True, True])) # True
print(all([True, False, True])) # False
# 实际应用
numbers = [1, 2, 3, 4, 5]
print(all(n > 0 for n in numbers)) # True
print(any(n % 2 == 0 for n in numbers)) # True
综合实战
实战1: 通讯录管理系统
python
class ContactBook:
def __init__(self):
self.contacts = {}
def add_contact(self):
"""添加联系人"""
name = input("姓名: ")
if name in self.contacts:
print("联系人已存在!")
return
phone = input("电话: ")
email = input("邮箱: ")
address = input("地址: ")
self.contacts[name] = {
"phone": phone,
"email": email,
"address": address
}
print(f"联系人 {name} 添加成功!")
def search_contact(self):
"""搜索联系人"""
keyword = input("请输入搜索关键词: ")
results = {name: info for name, info in self.contacts.items()
if keyword in name}
if not results:
print("未找到匹配的联系人")
else:
print(f"\n找到 {len(results)} 个结果:")
for name, info in results.items():
print(f"\n姓名: {name}")
print(f"电话: {info['phone']}")
print(f"邮箱: {info['email']}")
print(f"地址: {info['address']}")
def delete_contact(self):
"""删除联系人"""
name = input("请输入要删除的联系人姓名: ")
if name in self.contacts:
del self.contacts[name]
print(f"联系人 {name} 已删除")
else:
print("联系人不存在")
def show_all_contacts(self):
"""显示所有联系人"""
if not self.contacts:
print("通讯录为空")
return
print("\n" + "=" * 50)
print(f"{'姓名':<10}{'电话':<15}{'邮箱':<20}{'地址'}")
print("=" * 50)
for name, info in sorted(self.contacts.items()):
print(f"{name:<10}{info['phone']:<15}{info['email']:<20}{info['address']}")
print("=" * 50)
print(f"共 {len(self.contacts)} 个联系人")
def update_contact(self):
"""更新联系人"""
name = input("请输入要更新的联系人姓名: ")
if name not in self.contacts:
print("联系人不存在")
return
print("直接回车保留原值")
phone = input(f"电话 ({self.contacts[name]['phone']}): ")
email = input(f"邮箱 ({self.contacts[name]['email']}): ")
address = input(f"地址 ({self.contacts[name]['address']}): ")
if phone:
self.contacts[name]["phone"] = phone
if email:
self.contacts[name]["email"] = email
if address:
self.contacts[name]["address"] = address
print("联系人信息已更新")
def main():
book = ContactBook()
while True:
print("\n=== 通讯录管理系统 ===")
print("1. 添加联系人")
print("2. 搜索联系人")
print("3. 删除联系人")
print("4. 查看所有联系人")
print("5. 更新联系人")
print("6. 退出")
choice = input("请选择操作: ")
match choice:
case "1":
book.add_contact()
case "2":
book.search_contact()
case "3":
book.delete_contact()
case "4":
book.show_all_contacts()
case "5":
book.update_contact()
case "6":
print("感谢使用,再见!")
break
case _:
print("无效选择")
if __name__ == "__main__":
main()
实战2: 单词频率统计器
python
import re
from collections import Counter
def analyze_text(text):
"""分析文本"""
# 提取单词(只保留字母和数字)
words = re.findall(r'\b[a-zA-Z0-9]+\b', text.lower())
if not words:
print("未找到有效单词")
return
# 统计词频
word_counts = Counter(words)
# 基本信息
total_words = len(words)
unique_words = len(word_counts)
print("=" * 50)
print(" 文本分析报告")
print("=" * 50)
print(f"总单词数: {total_words}")
print(f"不同单词数: {unique_words}")
print(f"平均词长: {sum(len(w) for w in words) / total_words:.2f}")
# Top 10 高频词
print("\nTop 10 高频词:")
print(f"{'排名':<6}{'单词':<15}{'次数':<8}{'频率'}")
print("-" * 50)
for rank, (word, count) in enumerate(word_counts.most_common(10), 1):
frequency = count / total_words * 100
print(f"{rank:<6}{word:<15}{count:<8}{frequency:.2f}%")
# 词长分布
length_dist = Counter(len(word) for word in words)
print("\n词长分布:")
for length in sorted(length_dist.keys()):
count = length_dist[length]
percentage = count / total_words * 100
bar = "█" * int(percentage / 2)
print(f"{length:2d} 字母: {count:4d} ({percentage:5.2f}%) {bar}")
# 测试
sample_text = """
Python is a great programming language. Python is easy to learn.
Many developers love Python because Python is powerful and versatile.
Programming in Python is fun and productive.
"""
analyze_text(sample_text)
# 交互式
print("\n" + "=" * 50)
user_text = input("请输入要分析的文本: ")
analyze_text(user_text)
实战3: 待办事项管理器
python
import json
from datetime import datetime
class TodoManager:
def __init__(self, filename="todos.json"):
self.filename = filename
self.todos = self.load_todos()
def load_todos(self):
"""加载待办事项"""
try:
with open(self.filename, "r", encoding="utf-8") as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return []
def save_todos(self):
"""保存待办事项"""
with open(self.filename, "w", encoding="utf-8") as f:
json.dump(self.todos, f, ensure_ascii=False, indent=2)
def add_todo(self):
"""添加待办事项"""
title = input("任务标题: ")
priority = input("优先级 (高/中/低,默认中): ") or "中"
due_date = input("截止日期 (YYYY-MM-DD,可选): ")
todo = {
"id": len(self.todos) + 1,
"title": title,
"priority": priority,
"due_date": due_date if due_date else None,
"completed": False,
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.todos.append(todo)
self.save_todos()
print(f"任务 '{title}' 添加成功!")
def show_todos(self, show_completed=False):
"""显示待办事项"""
if not self.todos:
print("暂无待办事项")
return
# 过滤
filtered = [t for t in self.todos if show_completed or not t["completed"]]
if not filtered:
print("没有符合条件的任务")
return
# 排序:未完成优先,然后按优先级
priority_order = {"高": 0, "中": 1, "低": 2}
filtered.sort(key=lambda t: (t["completed"], priority_order.get(t["priority"], 1)))
print("\n" + "=" * 70)
print(f"{'ID':<4}{'状态':<6}{'优先级':<6}{'标题':<20}{'截止日期':<12}{'创建时间'}")
print("=" * 70)
for todo in filtered:
status = "✓" if todo["completed"] else "○"
due = todo["due_date"] or "-"
print(f"{todo['id']:<4}{status:<6}{todo['priority']:<6}"
f"{todo['title']:<20}{due:<12}{todo['created_at']}")
print("=" * 70)
completed = sum(1 for t in self.todos if t["completed"])
print(f"总计: {len(self.todos)} | 已完成: {completed} | 未完成: {len(self.todos) - completed}")
def complete_todo(self):
"""完成任务"""
try:
todo_id = int(input("请输入任务ID: "))
todo = next((t for t in self.todos if t["id"] == todo_id), None)
if todo:
todo["completed"] = True
todo["completed_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.save_todos()
print(f"任务 '{todo['title']}' 已完成!")
else:
print("任务不存在")
except ValueError:
print("请输入有效的ID")
def delete_todo(self):
"""删除任务"""
try:
todo_id = int(input("请输入要删除的任务ID: "))
todo = next((t for t in self.todos if t["id"] == todo_id), None)
if todo:
self.todos.remove(todo)
self.save_todos()
print(f"任务 '{todo['title']}' 已删除")
else:
print("任务不存在")
except ValueError:
print("请输入有效的ID")
def search_todos(self):
"""搜索任务"""
keyword = input("请输入搜索关键词: ")
results = [t for t in self.todos if keyword.lower() in t["title"].lower()]
if not results:
print("未找到匹配的任务")
else:
print(f"\n找到 {len(results)} 个结果:")
for todo in results:
status = "✓" if todo["completed"] else "○"
print(f"[{status}] ID:{todo['id']} {todo['title']}")
def main():
manager = TodoManager()
while True:
print("\n=== 待办事项管理器 ===")
print("1. 添加任务")
print("2. 查看任务")
print("3. 查看所有任务(包括已完成)")
print("4. 完成任务")
print("5. 删除任务")
print("6. 搜索任务")
print("7. 退出")
choice = input("请选择操作: ")
match choice:
case "1":
manager.add_todo()
case "2":
manager.show_todos()
case "3":
manager.show_todos(show_completed=True)
case "4":
manager.complete_todo()
case "5":
manager.delete_todo()
case "6":
manager.search_todos()
case "7":
print("感谢使用,再见!")
break
case _:
print("无效选择")
if __name__ == "__main__":
main()
实战4: 简易数据库查询系统
python
class SimpleDB:
def __init__(self):
self.tables = {}
def create_table(self, table_name, columns):
"""创建表"""
if table_name in self.tables:
print(f"表 '{table_name}' 已存在")
return
self.tables[table_name] = {
"columns": columns,
"data": []
}
print(f"表 '{table_name}' 创建成功")
def insert(self, table_name, record):
"""插入记录"""
if table_name not in self.tables:
print(f"表 '{table_name}' 不存在")
return
table = self.tables[table_name]
# 验证字段
for key in record.keys():
if key not in table["columns"]:
print(f"未知字段: {key}")
return
# 添加 ID
record["id"] = len(table["data"]) + 1
table["data"].append(record)
print(f"记录插入成功,ID: {record['id']}")
def select(self, table_name, conditions=None, order_by=None):
"""查询记录"""
if table_name not in self.tables:
print(f"表 '{table_name}' 不存在")
return []
table = self.tables[table_name]
results = table["data"].copy()
# 应用条件
if conditions:
filtered = []
for record in results:
match = True
for key, value in conditions.items():
if record.get(key) != value:
match = False
break
if match:
filtered.append(record)
results = filtered
# 排序
if order_by:
results.sort(key=lambda x: x.get(order_by, ""))
return results
def update(self, table_name, conditions, updates):
"""更新记录"""
if table_name not in self.tables:
print(f"表 '{table_name}' 不存在")
return 0
table = self.tables[table_name]
count = 0
for record in table["data"]:
match = all(record.get(k) == v for k, v in conditions.items())
if match:
record.update(updates)
count += 1
print(f"更新了 {count} 条记录")
return count
def delete(self, table_name, conditions):
"""删除记录"""
if table_name not in self.tables:
print(f"表 '{table_name}' 不存在")
return 0
table = self.tables[table_name]
original_count = len(table["data"])
table["data"] = [
record for record in table["data"]
if not all(record.get(k) == v for k, v in conditions.items())
]
deleted = original_count - len(table["data"])
print(f"删除了 {deleted} 条记录")
return deleted
def show_table(self, table_name):
"""显示表结构和数据"""
if table_name not in self.tables:
print(f"表 '{table_name}' 不存在")
return
table = self.tables[table_name]
print(f"\n表: {table_name}")
print(f"字段: {', '.join(table['columns'])}")
print(f"记录数: {len(table['data'])}")
if table["data"]:
print("\n数据:")
headers = table["columns"]
# 打印表头
header_str = " | ".join(f"{h:<15}" for h in headers)
print(header_str)
print("-" * len(header_str))
# 打印数据
for record in table["data"]:
row_str = " | ".join(f"{str(record.get(h, '')):<15}" for h in headers)
print(row_str)
def demo():
"""演示"""
db = SimpleDB()
# 创建表
db.create_table("students", ["name", "age", "major", "score"])
# 插入数据
db.insert("students", {"name": "张三", "age": 20, "major": "CS", "score": 90})
db.insert("students", {"name": "李四", "age": 22, "major": "Math", "score": 85})
db.insert("students", {"name": "王五", "age": 21, "major": "CS", "score": 92})
db.insert("students", {"name": "赵六", "age": 23, "major": "Physics", "score": 88})
# 显示表
db.show_table("students")
# 查询
print("\n=== 查询 CS 专业的学生 ===")
cs_students = db.select("students", {"major": "CS"})
for student in cs_students:
print(f" {student['name']}: {student['score']}分")
# 更新
print("\n=== 更新张三的成绩 ===")
db.update("students", {"name": "张三"}, {"score": 95})
# 删除
print("\n=== 删除赵六的记录 ===")
db.delete("students", {"name": "赵六"})
# 再次显示
db.show_table("students")
if __name__ == "__main__":
demo()
常见错误与注意事项
1. 可变对象的引用问题
python
# ❌ 陷阱:列表引用
list1 = [1, 2, 3]
list2 = list1
list2.append(4)
print(list1) # [1, 2, 3, 4](被意外修改)
# ✅ 正确:创建副本
list1 = [1, 2, 3]
list2 = list1.copy() # 或 list2 = list1[:]
list2.append(4)
print(list1) # [1, 2, 3]
# 对于嵌套结构,使用深拷贝
import copy
nested = [[1, 2], [3, 4]]
nested_copy = copy.deepcopy(nested)
2. 字典键的要求
python
# ✅ 可哈希的类型可以作为键
d = {
"string": 1,
42: 2,
(1, 2): 3,
frozenset([1, 2]): 4
}
# ❌ 不可哈希的类型不能作为键
# d = {[1, 2]: 5} # TypeError
# d = {{1, 2}: 6} # TypeError
3. 遍历时修改容器
python
# ❌ 危险:遍历时删除
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # 可能跳过元素
# ✅ 正确:创建新列表
numbers = [num for num in numbers if num % 2 != 0]
# ✅ 或者反向遍历
for num in reversed(numbers):
if num % 2 == 0:
numbers.remove(num)
4. 集合的空集创建
python
# ❌ 错误:{} 是空字典
empty = {}
print(type(empty)) # <class 'dict'>
# ✅ 正确:使用 set()
empty_set = set()
print(type(empty_set)) # <class 'set'>
5. 字符串的不可变性
python
# ❌ 不能直接修改字符串
# s = "hello"
# s[0] = "H" # TypeError
# ✅ 创建新字符串
s = "hello"
s = "H" + s[1:]
print(s) # Hello
# 或使用 replace
s = "hello"
s = s.replace("h", "H")
小结
| 容器类型 | 可变性 | 有序性 | 重复元素 | 典型用途 |
|---|---|---|---|---|
| list | ✅ | ✅ | ✅ | 存储有序集合 |
| tuple | ❌ | ✅ | ✅ | 固定数据、字典键 |
| dict | ✅ | ✅* | 键唯一 | 键值对映射 |
| set | ✅ | ❌ | ❌ | 去重、集合运算 |
| str | ❌ | ✅ | ✅ | 文本处理 |
*Python 3.7+ 字典保持插入顺序
核心要点:
- 列表最灵活,适合大多数场景
- 元组不可变,适合固定数据
- 字典用于键值对映射
- 集合用于去重和集合运算
- 字符串是不可变的字符序列
- 注意可变对象的引用问题
- 选择合适的容器能提升性能和代码可读性
掌握容器数据类型是 Python 编程的核心技能!