摘要:这是一份旨在帮助新手小白“完全掌握” Python 的系统性知识清单。本文不只罗列语法,更深入到底层内存原理、工程化最佳实践以及高级特性。涵盖基础数据类型、流程控制、函数式编程、面向对象 (OOP)、文件 I/O、并发编程、常用标准库及实战案例。建议收藏反复研读。
目录
第一阶段:Python 基石 (环境、变量与内存原理)
1.1 环境与基本概念
1.2 变量与动态类型 (核心)
1.3 命名规范 (PEP 8)
1.4 输入与输出
第二阶段:核心数据容器 (六脉神剑与 collections)
2.1 字符串 (String) —— 不可变序列
2.2 列表 (List) —— 可变有序序列
2.3 元组 (Tuple) —— 不可变序列
2.4 字典 (Dictionary) —— 键值对映射 (Hash Map)
2.5 集合 (Set) —— 无序不重复
2.6 高级容器 (collections 模块)
第三阶段:逻辑控制 (流程骨架与 Pattern Matching)
3.1 分支结构
3.2 模式匹配 (match…case) (Python 3.10+)
3.3 循环结构
第四阶段:函数编程 (作用域、闭包与递归)
4.1 参数详解 (四大金刚)
4.2 Lambda 表达式
4.3 作用域 (LEGB 原则)
第五阶段:黑魔法 (装饰器、生成器与迭代器)
5.1 装饰器 (Decorator)
5.2 生成器 (Generator) & 迭代器 (Iterator)
第六阶段:面向对象编程 (OOP 深度剖析)
6.1 类与对象
6.2 三大特性
6.3 属性装饰器 @property
6.4 类方法与静态方法
6.5 常用魔术方法 (Magic Methods)
第七阶段:文件 I/O、异常处理与序列化
7.1 文件读写与上下文管理器
7.2 现代路径库 pathlib (Python 3.4+)
7.3 异常处理
7.4 序列化 (JSON)
第八阶段:常用标准库 (Regex, OS, Time, Logging)
8.1 正则表达式 (re 模块)
8.2 时间与日期 (time, datetime)
8.3 系统操作 (os, sys)
8.4 日志系统 (logging)
第九阶段:并发编程与网络基础
9.1 并发与并行
9.2 网络请求 (requests 库)
第十阶段:工程化最佳实践
10.1 避坑指南 (易错点)
10.2 包管理 (PIP)
10.3 虚拟环境 (Virtualenv) —— 必学
10.4 类型注解 (Type Hints)
第十一阶段:终极实战案例
案例 1:简易图书管理系统 (基础综合)
案例 2:个人记账本 Pro (工程化综合)
结语
第一阶段:Python 基石 (环境、变量与内存原理)
1.1 环境与基本概念
-
解释型语言:Python 代码逐行解释执行,开发效率高。
-
注释:
-
单行注释:# 这是注释
-
多行注释:''' … ''' 或 """ … """ (常用于函数/类文档说明 Docstring)。
-
-
缩进 (Indentation):Python 的灵魂。必须严格对齐(官方 PEP 8 推荐 4 个空格,严禁 Tab 和空格混用)。
1.2 变量与动态类型 (核心)
-
概念:变量是内存中对象的“标签”或“引用”,而非存储数据的盒子。
-
动态类型:不需要声明类型,赋值即定义。
-
垃圾回收 (GC):基于引用计数机制。当一个对象的引用计数为 0 时,会被自动回收。
x = 10 # x 指向整数对象 10
x = "Hello" # x 改为指向字符串对象 "Hello" (旧的 10 如果没人用会被回收)
1.3 命名规范 (PEP 8)
-
变量/函数:snake_case (小写加下划线,如 user_name, get_data)。
-
类名:CamelCase (大驼峰,如 UserInfo, HttpClient)。
-
常量:ALL_CAPS (全大写,如 MAX_CONNECTIONS = 100)。
-
私有变量:_variable (约定私有),__variable (强制私有,名称修饰)。
1.4 输入与输出
-
输出 print():
-
print("A", "B", sep="|") $\\rightarrow$ 输出 A|B。
-
print("Loading…", end="") $\\rightarrow$ 不换行,适合制作进度条。
-
-
输入 input() (新手必坑):
-
接收到的永远是字符串。
-
案例:
age = input("请输入年龄: ") # 输入 18
# print(age + 1) # 报错!str 不能和 int 相加
real_age = int(age) # 必须显式转换
-
第二阶段:核心数据容器 (六脉神剑与 collections)
2.1 字符串 (String) —— 不可变序列
-
定义:单引号 '、双引号 "、三引号 """。
-
切片 (Slicing) [重中之重]:s[start:end:step]
-
s[0] (首), s[-1] (尾)。
-
s[1:4] (左闭右开,取索引 1, 2, 3)。
-
s[::-1] (反转字符串)。
-
-
常用方法 (修改操作均返回新字符串):
-
s.strip(): 去除首尾空白 (清洗数据必备)。
-
s.split(","): 按分隔符拆分为列表。
-
"-".join(list): 将列表拼接为字符串。
-
s.replace("old", "new"): 替换。
-
s.find("sub"): 查找索引 (找不到返回 -1)。
-
s.startswith("Pre") / s.endswith("Fix"): 判断开头/结尾。
-
s.isdigit(): 判断是否纯数字。
-
-
格式化 :
#f-strings (插值格式化字符串)
name = "small铁柱"; score = 98.567
print(f"User {name} got {score:.2f}") # 保留两位小数#str.format() 方法
print("你好, 我是 {}。".format(name))
# 指定参数名(更清晰)
print("你好, 我是 {n}, 今年 {a} 岁。".format(n=name, a=24))
# 指定位置索引
print("你好, {0}, 欢迎来到 {1}。".format("用户", "Python"))# % 操作符
age = 24
# %s 表示字符串,%d 表示整数
print("你好, 我是 %s, 今年 %d 岁。" % (name, age))
2.2 列表 (List) —— 可变有序序列
-
增:
-
lst.append(x): 末尾追加 (O(1),最快)。
-
lst.extend([a,b]): 追加一组。
-
lst.insert(i, x): 指定位置插入 (O(n),慎用)。
-
-
删:
-
lst.pop(): 弹出末尾元素 (栈操作)。
-
lst.pop(i): 弹出指定索引元素。
-
lst.remove(x): 删除第一个出现的值 x。
-
del lst[i]: 关键字删除。
-
lst.clear(): 清空列表。
-
-
查/改:lst[0] = "New", if "x" in lst:.
-
排序:lst.sort(reverse=True) (原地修改), sorted(lst) (返回新列表)。
-
列表推导式 (List Comprehension) (Python 灵魂):
# 生成 0-9 偶数的平方
squares = [x**2 for x in range(10) if x % 2 == 0]
2.3 元组 (Tuple) —— 不可变序列
-
定义:t = (1, 2)。
-
单元素陷阱:t = (1,) 必须加逗号,否则是整数。
-
作用:保护数据不被修改、作为字典 Key、节省内存。
-
拆包 (Unpacking):
x, y = (10, 20)
head, *body, tail = [1, 2, 3, 4, 5] # head=1, tail=5, body=[2,3,4]
2.4 字典 (Dictionary) —— 键值对映射 (Hash Map)
-
底层原理:哈希表。查找速度极快 O(1)。Key 必须唯一且不可变 (字符串/元组/数字)。
-
增/改:d["key"] = value。
-
合并 (Python 3.9+):d3 = d1 | d2。
-
查:
-
d["key"]: 不存在报错 KeyError,如果不存在这个键则会在字典中添加键值对。
-
d.get("key", "default"): 推荐,不存在返回默认值。
-
-
遍历:
for k, v in d.items():
print(k, v) -
字典推导式:
d = {} # 1. 先建一个空字典
for i in range(5): # 2. 开始循环
d[i] = i**2 # 3. 赋值:d[键] = 值
print(d)
#等价于
d = {i: i**2 for i in range(5)}
2.5 集合 (Set) —— 无序不重复
-
定义:s = {1, 2}。空集合必须用 set(),因为 {} 是空字典。
-
作用:极速去重、数学运算。
-
运算:
-
s1 & s2 (交集)
-
s1 | s2 (并集)
-
s1 – s2 (差集)
-
s1 ^ s2 (对称差集)
-
2.6 高级容器 (collections 模块)
-
Counter: 统计词频。
from collections import Counter
print(Counter("banana")) # {'a': 3, 'n': 2, 'b': 1} -
defaultdict: 带默认值的字典,解决 KeyError。
-
namedtuple:以此访问元组元素 Point(x=1, y=2)。
第三阶段:逻辑控制 (流程骨架与 Pattern Matching)
3.1 分支结构
-
真值检测:在 Python 中,0, "", [], {}, None, False 均为 假,其余为 真。
if not user_list: # 如果列表为空 (Pythonic 写法)
print("无数据")
elif len(user_list) > 10:
print("数据过多")
else:
print("正常") -
三元运算符:
#如果x大于y则返回下,否则返回y
res = x if x > y else y
-
海象运算符 (:=) (Python 3.8+):
-
在表达式中同时赋值和判断。
#赋值表达式,将运算和赋值合并,简洁高效
if (n := len(data)) > 10:
print(f"长度 {n} 太长了") -
3.2 模式匹配 (match…case) (Python 3.10+)
-
类似于其他语言的 Switch-Case,但更强大。
#将status和case后面的值以一比对,匹配成功则执行对应的代码段
#不需要 break, match 匹配成功一个后会自动停止,不会“穿透”到下一个 case。
#并且最后一个必须是case _
status = 404
match status:
case 200:
print("OK")
case 404 | 403: # 匹配多个
print("Not Allowed")
case _: # 默认情况 (相当于 default)
print("Unknown")
3.3 循环结构
-
range(): range(start, stop, step),左闭右开生成器(顾头不顾尾)。
-
for 循环: 遍历任何可迭代对象 (List, Str, Dict, File)。
-
while 循环: 基于条件的循环。
-
控制语句:
-
break: 立即终止循环。
-
continue: 跳过本次,进入下一次。
-
pass: 占位符,什么都不做。
-
-
高级用法: for…else / while…else:
-
逻辑:只有循环正常结束 (没有遇到 break) 时才执行 else。
-
场景: 搜索不到结果时的兜底操作。
for item in box:
if item == "key":
print("Found it!")
break
else:
print("Not found in box.") -
第四阶段:函数编程 (作用域、闭包与递归)
4.1 参数详解 (四大金刚)
好的,这部分是 Python 函数定义中最灵活、也是最容易出错(特别是默认参数陷阱)的地方。
我将用生活化的案例结合代码,把这“四大金刚”逐一拆解清楚。
1. 位置参数 (Positional Arguments)
- 口诀:“一个萝卜一个坑,排排坐,不能乱。”
- 规则:调用函数时,传入参数的顺序必须和定义时的顺序完全一致,且数量必须相同。
- 案例:去星巴克点单(先说杯型,再说咖啡名)。 def make_coffee(size, coffee_type):
print(f"为您制作一杯 {size} 的 {coffee_type}")# ✅ 正确:顺序一致
make_coffee("大杯", "拿铁")
# 输出: 为您制作一杯 大杯 的 拿铁# ❌ 错误:顺序反了,逻辑变奇怪
make_coffee("拿铁", "大杯")
# 输出: 为您制作一杯 拿铁 的 大杯 (虽然没报错,但逻辑错了)# ❌ 错误:少传参数
# make_coffee("大杯")
# 报错: TypeError: missing 1 required positional argument
2. 关键字参数 (Keyword Arguments)
- 口诀:“指名道姓,顺序无所谓。”
- 规则:调用时明确写出 参数名=值,这样就可以不按顺序传参了。
- 案例:填快递单(只要写了“收件人:张三”,“电话:123”,写在哪一行都行)。 def send_parcel(name, address):
print(f"寄给: {name}, 地址: {address}")# ✅ 正确:顺序打乱也没事,因为指名道姓了
send_parcel(address="北京朝阳区", name="张三")
# 输出: 寄给: 张三, 地址: 北京朝阳区# 混合使用注意点:位置参数必须在关键字参数之前!
# send_parcel(address="北京", "张三") # ❌ 报错!Python 不知道 "张三" 是谁
3. 默认参数陷阱 (Default Argument Trap) —— 高频面试题
- 口诀:“默认值只在函数定义时创建一次,不要用可变对象(列表/字典)做默认值。”
- 这是新手最容易踩的坑。
- 错误示范 (列表作为默认参数)
- 想象一下,你定义了一个函数,默认给客人一个空盘子装水果。你以为每次客人来都会拿个新盘子,但实际上 Python 只在第一次开店时造了一个盘子,所有人共用这一个盘子。 def add_fruit(fruit, plate=[]): # plate 是可变列表
plate.append(fruit)
return plate# 客人 A 来了,没带盘子,用默认的
print(add_fruit("苹果"))
# 输出: ['苹果'] -> 正常# 客人 B 来了,也没带盘子,用默认的
# 你以为会输出 ['香蕉'],但实际上…
print(add_fruit("香蕉"))
# 输出: ['苹果', '香蕉'] -> A 吃的苹果还在盘子里!# 客人 C 来了
print(add_fruit("梨"))
# 输出: ['苹果', '香蕉', '梨'] -> 越来越乱 - 正确示范 (使用 None 作为哨兵)
- 我们规定:默认不发盘子 (None)。如果客人没带盘子,我再临时给你拿个新的。 def add_fruit_safe(fruit, plate=None): # ✅ 安全
if plate is None:
plate = [] # 每次调用时,新创建一个空列表
plate.append(fruit)
return plateprint(add_fruit_safe("苹果")) # ['苹果']
print(add_fruit_safe("香蕉")) # ['香蕉'] -> 终于正常了,大家各吃各的
4. 不定长参数 (*args 和 **kwargs)
场景:当你不知道用户会传多少个参数时使用。
① *args (星号元组)
- 作用:专门接收多出来的位置参数,把它们打包成一个 元组 (tuple)。
- 案例:吃火锅,必点锅底,剩下的配菜想点多少点多少。 def hotpot(soup, *foods):
print(f"锅底: {soup}")
print(f"配菜 (args类型为 {type(foods)}): {foods}")# 调用
hotpot("麻辣锅", "牛肉", "毛肚", "生菜")# 输出:
# 锅底: 麻辣锅
# 配菜 (args类型为 <class 'tuple'>): ('牛肉', '毛肚', '生菜')
② **kwargs (双星号字典)
- 作用:专门接收多出来的关键字参数,把它们打包成一个 字典 (dict)。kwargs 是 "keyword arguments" 的缩写。
- 案例:用户注册,必填用户名,剩下的性别、年龄、爱好随你填不填。 def register(username, **info):
print(f"用户: {username}")
print(f"详细信息 (kwargs类型为 {type(info)}): {info}")# 调用
register("admin", age=18, city="Shanghai", hobby="Coding")# 输出:
# 用户: admin
# 详细信息 (kwargs类型为 <class 'dict'>): {'age': 18, 'city': 'Shanghai', 'hobby': 'Coding'}
5. 终极合体 (万能参数公式)
- 如果把它们全凑在一起,必须严格遵守以下顺序:
- def func(位置参数, 默认参数, *args, **kwargs) def super_func(a, b=10, *args, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"kwargs={kwargs}")super_func(1, 2, 3, 4, name="Ai", key="123")
# 输出:
# a=1, b=2
# args=(3, 4) <- 多余的位置参数进了元组
# kwargs={'name': 'Ai', 'key': '123'} <- 多余的关键字参数进了字典
这个 super_func 结构在查看 Python 源码或写装饰器时非常常见,理解了它,你就看懂了一半的 Python 高级代码。
4.2 Lambda 表达式
-
匿名函数,用于简单的单行逻辑,常配合 map, sort, filter 使用。
-
格式:lambda 参数列表 : 表达式
-
表达式只能有一行代码,会自动return
- 配合 sort / max / min (排序与查找) —— 最常用 users = [
{'name': 'Tom', 'age': 20},
{'name': 'Jerry', 'age': 5},
{'name': 'Spike', 'age': 10}
]
# 按字典中的 age 字段排序
#格式:lambda 参数列表 : 表达式
#表达式只能有一行代码,会自动returnusers.sort(key=lambda x: x['age']) #按照字典里面的age对列表排序
- 配合 map (映射/批量处理)
- map(函数, 列表):把列表里的每一个元素,都丢给函数处理一遍,生成新列表。 #把列表 [1, 2, 3] 里的每个数都乘以 10
nums = [1, 2, 3]# 这里的 lambda x: x*10 就是处理逻辑
result = list(map(lambda x: x * 10, nums))
print(result) # [10, 20, 30]
- map(函数, 列表):把列表里的每一个元素,都丢给函数处理一遍,生成新列表。 #把列表 [1, 2, 3] 里的每个数都乘以 10
- 配合 filter (过滤/筛选)
- filter(函数, 列表):把列表里的元素丢给函数,如果函数返回 True 就保留,False 就丢弃。 #只保留列表中的偶数
nums = [1, 2, 3, 4, 5, 6]# x % 2 == 0 返回 True 则保留
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # [2, 4, 6]
- filter(函数, 列表):把列表里的元素丢给函数,如果函数返回 True 就保留,False 就丢弃。 #只保留列表中的偶数
4.3 作用域 (LEGB 原则)
-
查找顺序:Local (本地) $\\rightarrow$ Enclosing (闭包外层) $\\rightarrow$ Global (全局) $\\rightarrow$ Built-in (内置)。
-
global: 在函数内修改全局变量。
-
nonlocal: 在内层函数修改外层函数的变量 (闭包常用)。
第五阶段:黑魔法 (装饰器、生成器与迭代器)
5.1 装饰器 (Decorator)
-
核心:闭包的应用。在不修改原函数代码的前提下,增加功能 (日志、计时、鉴权、缓存)。
-
语法:@装饰器名
import time
from functools import wrapsdef timer(func):
@wraps(func) # 保留原函数的元数据 (name, doc)
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
print(f"耗时: {time.time() – start:.4f}s")
return res
return wrapper@timer
def heavy_work():
time.sleep(1)
5.2 生成器 (Generator) & 迭代器 (Iterator)
-
迭代器: 实现了 __iter__ 和 __next__ 的对象。
-
生成器: 使用 yield 的函数。
-
Yield: 函数暂停并产出值,保留上下文,下次调用继续。
-
优势: 省内存。处理海量数据时,用一个生成一个。
-
-
生成器表达式:
# 列表推导式 (耗内存): [x**2 for x in range(1000000)]
# 生成器表达式 (省内存):
gen = (x**2 for x in range(1000000))
print(next(gen)) # 0
第六阶段:面向对象编程 (OOP 深度剖析)
6.1 类与对象
-
Class (类): 图纸。
-
Object (对象): 实体。
-
self: 实例自身的引用。
-
__init__: 构造函数,初始化属性。
6.2 三大特性
封装: 使用 _ (受保护) 和 __ (私有) 隐藏属性。
继承: class Dog(Animal):。子类拥有父类的方法。
多态: 不同对象调用相同方法名,产生不同行为。
6.3 属性装饰器 @property
-
将方法伪装成属性,实现 Getter/Setter 逻辑,进行数据校验。
class Person:
def __init__(self):
self._score = 0@property
def score(self):
return self._score@score.setter
def score(self, val):
if not 0 <= val <= 100: raise ValueError("分数非法")
self._score = val
6.4 类方法与静态方法
-
@classmethod: 第一个参数是 cls,通常用于工厂模式。
-
@staticmethod: 没有任何默认参数,仅仅是归类在类里的普通函数。
6.5 常用魔术方法 (Magic Methods)
-
__str__: 用户看到的字符串 (print 调用)。
-
__repr__: 开发者看到的字符串 (调试用)。
-
__call__: 让对象像函数一样被调用 obj()。
-
__len__: 定义 len(obj) 的行为。
-
__getitem__ / __setitem__: 让对象支持索引操作 obj[key]。
第七阶段:文件 I/O、异常处理与序列化
7.1 文件读写与上下文管理器
-
强烈推荐:使用 with open(…) 自动关闭文件,防止资源泄露。
-
模式:'r'(读), 'w'(覆盖写), 'a'(追加), 'rb'(二进制读), 'w+'(读写)。
7.2 现代路径库 pathlib (Python 3.4+)
-
完全替代 os.path,面向对象。
from pathlib import Path
p = Path("data") / "sub" / "file.txt" # 路径拼接使用 /
if not p.parent.exists():
p.parent.mkdir(parents=True) # 自动创建父目录p.write_text("Hello", encoding="utf-8") # 一行写入
content = p.read_text(encoding="utf-8") # 一行读取
7.3 异常处理
-
EAFP 原则: "Ask for forgiveness, not permission" (先做,报错了再捕获)。
-
结构:
try:
# 可能报错的代码
except ValueError as e:
# 处理特定错误
except Exception as e:
# 处理未知错误
else:
# 无异常时执行
finally:
# 无论是否报错都执行 (如关闭数据库连接)
7.4 序列化 (JSON)
-
json.dumps(obj, ensure_ascii=False): 对象转字符串 (支持中文)。
-
json.loads(str): 字符串转对象。
第八阶段:常用标准库 (Regex, OS, Time, Logging)
8.1 正则表达式 (re 模块)
-
处理文本的神器。
-
re.match(): 从头匹配。
-
re.search(): 搜索第一个。
-
re.findall(): 找所有。
-
re.sub(): 替换。
-
常用符号: \\d (数字), \\w (字符), . (任意), * (0次或多次), + (1次或多次), ? (0或1次)。
8.2 时间与日期 (time, datetime)
-
time.sleep(n): 休眠。
-
time.time(): 时间戳。
-
datetime.now().strftime("%Y-%m-%d"): 格式化时间。
8.3 系统操作 (os, sys)
-
os.listdir(): 列出文件。
-
os.environ: 获取环境变量。
-
sys.argv: 获取命令行参数。
-
sys.path: 模块搜索路径。
8.4 日志系统 (logging)
-
别再用 print 了! 生产环境必须用 logging。
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s – %(levelname)s – %(message)s')
logging.info("程序启动")
logging.error("发生严重错误")
第九阶段:并发编程与网络基础
9.1 并发与并行
-
GIL (全局解释器锁): 限制同一时刻只有一个线程在 CPU 执行。导致 Python 多线程适合 IO 密集型 (爬虫),不适合 CPU 密集型 (计算)。
-
threading: 多线程。
import threading
t = threading.Thread(target=my_func, args=(1,))
t.start()
t.join() # 等待线程结束 -
multiprocessing: 多进程 (绕过 GIL,利用多核 CPU)。
9.2 网络请求 (requests 库)
-
虽然是第三方库,但已成为标准。
# pip install requests
import requests
resp = requests.get("https://api.github.com")
print(resp.status_code)
print(resp.json())
第十阶段:工程化最佳实践
10.1 避坑指南 (易错点)
is vs ==: is 比较内存地址,== 比较值。判断 None 必须用 is None。
深浅拷贝:
-
l2 = l1: 引用赋值。
-
copy.copy(): 浅拷贝 (只拷第一层)。
-
copy.deepcopy(): 深拷贝 (递归完全独立)。
闭包延迟绑定: 循环中创建 lambda 时,变量值是循环结束时的值。
10.2 包管理 (PIP)
-
pip install <package>: 安装。
-
pip freeze > requirements.txt: 导出依赖。
-
pip install -r requirements.txt: 一键安装。
10.3 虚拟环境 (Virtualenv) —— 必学
-
防止不同项目包版本冲突。
python -m venv venv # 创建
source venv/bin/activate # 激活 (Linux/Mac)
.\\venv\\Scripts\\activate # 激活 (Windows)
10.4 类型注解 (Type Hints)
-
Python 3.5+ 引入,方便 IDE 提示。
def add(a: int, b: int) -> int:
return a + b
第十一阶段:终极实战案例
案例 1:简易图书管理系统 (基础综合)
(涉及:列表、字典、循环、函数、异常处理)
books = [{"id": 1, "title": "Python Basics", "status": "ok"}]
def borrow_book(bid):
for book in books:
if book['id'] == bid:
if book['status'] == "ok":
book['status'] = "out"
print(f"借阅成功: {book['title']}")
return
else:
print("已被借出")
return
print("查无此书")
案例 2:个人记账本 Pro (工程化综合)
(涉及:Pathlib, JSON, 装饰器, 类型注解, 生成器表达式, Logging)
import json
import time
import logging
from pathlib import Path
from typing import List, Dict
# 配置日志
logging.basicConfig(level=logging.INFO)
DATA_FILE = Path("account.json")
# 装饰器:计算操作耗时
def log_time(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
# logging.info(f"Action cost: {time.time()-start:.4f}s")
return res
return wrapper
class AccountBook:
def __init__(self):
self.data: List[Dict] = self._load()
def _load(self) -> List[Dict]:
if not DATA_FILE.exists(): return []
try:
return json.loads(DATA_FILE.read_text("utf-8"))
except json.JSONDecodeError:
logging.error("数据文件损坏,重置为空")
return []
def _save(self):
# ensure_ascii=False 保证中文正常显示
DATA_FILE.write_text(json.dumps(self.data, ensure_ascii=False, indent=2), "utf-8")
@log_time
def add(self, item: str, cost: float):
record = {
"item": item,
"cost": cost,
"time": time.strftime("%Y-%m-%d %H:%M:%S")
}
self.data.append(record)
self._save()
print(f"✅ 已记录: {item} – {cost}")
def summary(self):
if not self.data:
print("暂无数据")
return
# 生成器表达式求和,内存高效
total = sum(x['cost'] for x in self.data)
print(f"\\n📊 总支出: {total:.2f} 元")
# 切片查看最近 5 笔
for i, d in enumerate(self.data[-5:], 1):
print(f"{i}. {d['time']} | {d['item']}: {d['cost']}")
if __name__ == "__main__":
book = AccountBook()
while True:
cmd = input("\\n[1]记账 [2]统计 [q]退出: ")
if cmd == '1':
try:
i = input("项目: ")
c = float(input("金额: "))
book.add(i, c)
except ValueError: print("❌ 金额输入错误")
elif cmd == '2':
book.summary()
elif cmd == 'q':
print("再见!")
break
结语
感谢您的点赞、收藏、关注,祝学习愉快!




