告别烂代码10个实用技巧让你的Python程序更简洁、更高效🚀
📖 引言
哈喽,小伙伴们我是小甲鱼~ 🐟
今天要和大家聊聊一个非常重要的话题——Python代码优化
不知道你有没有遇到过这种情况:写了一段代码,跑是能跑,但总感觉哪里不对劲——要么太长太啰嗦,要么慢得像乌龟爬,再要么就是自己都看不懂自己写了啥 🤯
别慌今天小甲鱼就把自己压箱底的10个代码优化技巧全部拿出来,保证让你的代码从"又臭又长"变成"优雅又高效"
剧透一下:这些技巧都不难,小甲鱼保证初中生都能学会而且学会了之后,你写代码的效率至少提升一倍,不信往下看~
🔍 基础讲解
在正式开始之前,小甲鱼先和大家唠唠:为什么要优化代码
为什么要优化代码?
想象一下,你要去菜市场买菜:
代码优化主要有三个好处:
- 1. 读起来更爽——好的代码像读小说,烂的代码像读天书
- 2. 跑起来更快——优化过的代码,执行效率可能提升几十倍甚至几百倍
- 3. 维护更轻松——以后想改点啥,不用抓耳挠腮猜自己当初在想啥
好,废话不多说,让我们开始学习这10个技巧吧🎯
💡 技巧一:列表推导式——一行代码搞定循环
原来的写法
如果你想创建一个1到10的平方列表,你可能会这样写:
# 传统写法 - 又长又臭squares = []for i inrange(1, 11): squares.append(i ** 2)print(squares)# 输出: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
优化后的写法
# 列表推导式 - 一行搞定squares = [i ** 2for i inrange(1, 11)]print(squares)# 输出: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
还能加条件!
# 只保留偶数的平方even_squares = [i ** 2for i inrange(1, 11) if i % 2 == 0]print(even_squares)# 输出: [4, 16, 36, 64, 100]
小甲鱼说
列表推导式就是Python的魔法棒,轻轻一挥,循环+ append的组合就没了记住这个公式:
[表达式 for 变量 in 可迭代对象 if 条件]
---## 💡 技巧二:enumerate和zip——循环的神仙伴侣### 原来的写法如果你想同时遍历列表的索引和值:```python# 传统写法 - 麻烦!fruits = ['苹果', '香蕉', '橘子']for i in range(len(fruits)): print(f"第{i}个水果是: {fruits[i]}")# 输出:# 第0个水果是: 苹果# 第1个水果是: 香蕉# 第2个水果是: 橘子
优化后的写法
# enumerate - 自动给你索引fruits = ['苹果', '香蕉', '橘子']for i, fruit inenumerate(fruits, 1): # 从1开始计数print(f"第{i}个水果是: {fruit}")# 输出:# 第1个水果是: 苹果# 第2个水果是: 香蕉# 第3个水果是: 橘子
zip:同时遍历两个列表
# 同时遍历名字和年龄names = ['小明', '小红', '小刚']ages = [18, 20, 22]for name, age inzip(names, ages):print(f"{name}今年{age}岁")# 输出:# 小明今年18岁# 小红今年20岁# 小刚今年22岁
小甲鱼说
enumerate和zip就是Python给懒人准备的礼物再也不用手动管理索引了,省心又省力👍
💡 技巧三:生成器——省内存的神器
原来的写法
如果你要处理一个超大的列表:
# 一次性生成所有数据 - 内存爆炸警告!numbers = [i ** 2for i inrange(1000000)] # 这得占多少内存!for num in numbers:print(num)
优化后的写法
# 生成器 - 用多少取多少,不浪费!defsquare_generator(n):for i inrange(n):yield i ** 2# 使用生成器gen = square_generator(1000000)# 每次只取一个值,内存占用极低!for num in gen:print(num)if num > 100: # 演示一下,不需要遍历全部break# 输出:# 0# 1# 4# 9# 16# ...# 121
一行生成器
# 还能用圆括号创建生成器gen = (i ** 2for i inrange(1000000))print(next(gen)) # 0print(next(gen)) # 1print(next(gen)) # 4
小甲鱼说
生成器就像自来水龙头,随用随取,不用提前把整个水库装满处理大数据时,这是保命的技能💧
💡 技巧四:字典的安全访问——告别KeyError
原来的写法
# 传统写法 - 容易出错!person = {'name': '小明', 'age': 18}# 访问不存在的键会报错!print(person['gender']) # KeyError: 'gender'
优化后的写法
方法1:get()方法
person = {'name': '小明', 'age': 18}# get()方法 - 不存在就返回None,不会报错!gender = person.get('gender')print(gender) # None# 还能指定默认值gender = person.get('gender', '未知')print(gender) # 未知
方法2:setdefault()
person = {'name': '小明', 'age': 18}# 如果键不存在,就设置为默认值person.setdefault('gender', '未知')print(person) # {'name': '小明', 'age': 18, 'gender': '未知'}# 如果键已存在,就不改变person.setdefault('name', '小红')print(person['name']) # 小明(还是原来的值)
小甲鱼说
get()和setdefault()就是字典的安全气囊,关键时刻能救你的程序一命再也不用写一堆if key in dict的判断了🚗
💡 技巧五:f-string——最强大的字符串格式化
原来的写法
# 老式写法 - 麻烦!name = '小明'age = 18height = 1.75# %格式化print("我叫%s,今年%d岁,身高%.2f米" % (name, age, height))# format方法print("我叫{},今年{}岁,身高{:.2f}米".format(name, age, height))
优化后的写法
# f-string - 简单粗暴直接插入变量!name = '小明'age = 18height = 1.75print(f"我叫{name},今年{age}岁,身高{height:.2f}米")# 输出: 我叫小明,今年18岁,身高1.75米# 还能运算!print(f"明年我就{age + 1}岁了")# 输出: 明年我就19岁了
f-string的高级用法
# 格式化数字num = 1234.5678print(f"金额: {num:,.2f}") # 金额: 1,234.57# 对齐names = ['小明', '小红', '小刚']for name in names:print(f"{name:^10}爱你") # 居中对齐# 输出:# 小明 爱你# 小红 爱你# 小刚 爱你
小甲鱼说
f-string是Python 3.6引入的神器,简单程度直接秒杀其他所有格式化方式记住,变量名往大括号里一堆就能用,谁用谁知道😎
💡 技巧六:集合操作——去重和快速查找
原来的写法
# 想去掉列表中的重复元素?items = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]# 传统方法 - 麻烦!unique = []for item in items:if item notin unique: unique.append(item)print(unique) # [1, 2, 3, 4]
优化后的写法
# set - 一行搞定去重!items = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]unique = list(set(items))print(unique) # [1, 2, 3, 4]# 注意:set是无序的,如果需要保持顺序,可以用 dict.fromkeys()unique_ordered = list(dict.fromkeys(items))print(unique_ordered) # [1, 2, 3, 4]
集合的快速查找
# 判断元素是否在列表中 - O(n)复杂度items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]print(5in items) # True - 列表需要遍历# 判断元素是否在集合中 - O(1)复杂度items_set = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}print(5in items_set) # True - 集合直接定位,超级快!
集合运算
# 集合的交、并、差运算set_a = {1, 2, 3, 4, 5}set_b = {4, 5, 6, 7, 8}print(set_a | set_b) # 并集: {1, 2, 3, 4, 5, 6, 7, 8}print(set_a & set_b) # 交集: {4, 5}print(set_a - set_b) # 差集: {1, 2, 3}print(set_a ^ set_b) # 对称差集: {1, 2, 3, 6, 7, 8}
小甲鱼说
集合就是Python的超级英雄,去重、查找、集合运算,样样精通记住,如果你的代码需要频繁判断"在不在"列表里,赶紧换成set,速度提升不是一点半点🦸
💡 技巧七:装饰器——代码的复用神器
什么是装饰器?
装饰器可以在不修改原函数的情况下,给函数增加新功能就像给函数穿上一件外套
实战应用
# 定义一个装饰器 - 打印函数执行时间import timedeftimer(func):defwrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time()print(f"函数{func.__name__}执行了{end - start:.4f}秒")return resultreturn wrapper# 使用装饰器@timerdefslow_function(): time.sleep(1) # 模拟耗时操作return"执行完成!"# 调用函数result = slow_function()# 输出: 函数slow_function执行了1.0012秒
装饰器的常见用途
# 1. 日志记录deflog(func):defwrapper(*args, **kwargs):print(f"调用函数: {func.__name__}")return func(*args, **kwargs)return wrapper# 2. 权限检查defrequire_login(func):defwrapper(user):if user.get('is_login'):return func(user)else:return"请先登录!"return wrapper# 使用@require_logindefget_profile(user):returnf"欢迎{user['name']}!"# 测试user1 = {'name': '小明', 'is_login': True}user2 = {'name': '小红', 'is_login': False}print(get_profile(user1)) # 欢迎小明!print(get_profile(user2)) # 请先登录!
小甲鱼说
装饰器就是Python的瑞士军刀,一用一个准日志、权限检查、性能监控,统统一行代码搞定学会了这个,你就是同事眼中的大神🎩
💡 技巧八:with语句——资源管理的贴心管家
原来的写法
# 传统文件操作 - 容易忘记关闭!f = open('test.txt', 'w')f.write('你好')f.close() # 忘记关就麻烦了!# 如果中途出错,文件可能没关闭!# f = open('test.txt', 'w')# f.write('你好')# raise Exception("出错了!") # 这时候f.close()根本执行不到!
优化后的写法
# with语句 - 自动帮你关闭资源!withopen('test.txt', 'w', encoding='utf-8') as f: f.write('你好,小甲鱼!')# 即使这里出错,文件也会正确关闭# 文件自动关闭了,可以继续用withopen('test.txt', 'r', encoding='utf-8') as f: content = f.read()print(content) # 你好,小甲鱼!
with语句的原理
# 上下文管理器协议classMyContextManager:def__enter__(self):print("进入上下文")returnselfdef__exit__(self, exc_type, exc_val, exc_tb):print("退出上下文")# 如果返回True,异常会被吞掉returnFalsewith MyContextManager() as cm:print("在上下文中执行")# 即使出错,也会执行__exit__# 输出:# 进入上下文# 在上下文中执行# 退出上下文
小甲鱼说
with语句就是Python的贤内助,把资源管理得妥妥的文件、数据库、网络连接,用with就对了再也不用担心忘记close()了🏠
💡 技巧九:isinstance——更智能的类型检查
原来的写法
# 硬编码类型检查 - 不好!defprocess(data):iftype(data) == str:return data.upper()eliftype(data) == int:return data * 2eliftype(data) == list:returnsum(data)
优化后的写法
# isinstance - 支持继承关系!defprocess(data):ifisinstance(data, str):return data.upper()elifisinstance(data, (int, float)): # 同时检查多个类型return data * 2elifisinstance(data, list):returnsum(data)# 测试print(process("hello")) # HELLOprint(process(10)) # 20print(process(3.14)) # 6.28print(process([1, 2, 3])) # 6
isinstance的高级用法
# 检查自定义类classAnimal:passclassDog(Animal):passclassCat(Animal):passdog = Dog()# isinstance考虑继承关系print(isinstance(dog, Dog)) # Trueprint(isinstance(dog, Animal)) # True - Dog是Animal的子类!# type不考虑继承print(type(dog) == Animal) # False
鸭子类型
# 更好的方式:鸭子类型# 不要检查类型,而是检查行为defprocess(data):# 如果有upper方法,就调用它ifhasattr(data, 'upper'):return data.upper()# 如果可以相乘elifhasattr(data, '__mul__'):return data * 2# 如果可以求和elifhasattr(data, '__add__'):returnsum(data)# 这样更灵活,字符串、数字、列表都能处理!
小甲鱼说
isinstance就是Python的智能雷达,不仅能检测类型,还能检测子类而且要学会"鸭子类型"思维——不要问它是什么,要问它能做什么🦆
💡 技巧十:异常处理——让代码更健壮
原来的写法
# 用if判断来处理错误 - 代码又臭又长!defdivide(a, b):if b == 0:return"不能除以0!"else:return a / b# 每个地方都要判断,烦不烦?result = divide(10, 0)print(result)
优化后的写法
# 用try-except - 更优雅!defdivide(a, b):try:return a / bexcept ZeroDivisionError:return"不能除以0!"# 测试print(divide(10, 2)) # 5.0print(divide(10, 0)) # 不能除以0!
多个异常处理
# 处理多种异常defprocess(data):try: result = int(data) / 0return resultexcept ValueError:return"无法转换为数字"except ZeroDivisionError:return"不能除以0"except Exception as e:returnf"未知错误: {e}"print(process("abc")) # 无法转换为数字print(process("10")) # 不能除以0
try-except-else-finally
# 完整的异常处理结构try:# 尝试执行的代码 result = 10 / 2except ZeroDivisionError:# 发生ZeroDivisionError时执行print("除以0了!")else:# 没有异常时执行print(f"计算结果是{result}")finally:# 无论有没有异常都执行print("这段代码无论如何都会执行")# 输出:# 计算结果是5.0# 这段代码无论如何都会执行
异常处理实战
# 读取文件,兼容各种错误defread_file(filename):try:withopen(filename, 'r', encoding='utf-8') as f:return f.read()except FileNotFoundError:returnf"文件{filename}不存在"except PermissionError:returnf"没有权限读取{filename}"except UnicodeDecodeError:return"文件编码错误"# 完美!print(read_file('不存在的文件.txt')) # 文件不存在的文件.txt不存在
小甲鱼说
异常处理就是Python的安全网,程序出错了不会直接崩溃,而是优雅地处理记住,用try-except而不是if-else来处理异常,这是Python的哲学🕸️
🚀 实战应用
光说不练假把式小甲鱼这就带大家做一个实战项目,把今天学的技巧都用上
项目:学生信息管理系统
"""学生信息管理系统 v2.0用上我们今天学的所有技巧!"""classStudent:"""学生类"""def__init__(self, name, age, score):self.name = nameself.age = ageself.score = scoredef__repr__(self):returnf"Student(name='{self.name}', age={self.age}, score={self.score})"classStudentManager:"""学生管理系统 - 优化版"""def__init__(self):# 使用字典存储学生,id为键self.students = {}self.next_id = 1# 技巧七:装饰器 - 添加日志功能deflog_operation(func):"""记录操作日志的装饰器"""defwrapper(self, *args, **kwargs):print(f"\n[操作] 开始执行: {func.__name__}") result = func(self, *args, **kwargs)print(f"[操作] 完成: {func.__name__}")return resultreturn wrapper# 技巧一:列表推导式 - 快速添加学生 @log_operationdefadd_student(self, name, age, score):"""添加学生"""# 技巧四:字典安全访问 - 不需要# 技巧五:f-string - 格式化输出 student_id = self.next_idself.students[student_id] = Student(name, age, score)self.next_id += 1print(f"✅ 添加成功: {name}, 学号: {student_id}")return student_id @log_operationdefadd_multiple_students(self, student_list):"""批量添加学生 - 使用列表推导式"""# 列表推导式 + 生成器 student_ids = [self.add_student(name, age, score) for name, age, score in student_list ]print(f"✅ 批量添加了 {len(student_ids)} 个学生")return student_ids# 技巧二:enumerate - 遍历学生列表deflist_students(self):"""列出所有学生"""ifnotself.students:print("📭 还没有学生记录")returnprint("\n📋 学生列表:")print("-" * 50)# enumerate + f-stringfor i, (sid, student) inenumerate(self.students.items(), 1):print(f"{i}. 学号:{sid} | 姓名:{student.name} | "f"年龄:{student.age} | 分数:{student.score}")print("-" * 50)# 技巧三:生成器 - 遍历高分学生defget_top_scorers(self, threshold=60):"""获取高分学生 - 使用生成器"""# 生成器表达式return ( (sid, student) for sid, student inself.students.items() if student.score >= threshold )defshow_top_scorers(self, threshold=60):"""显示高分学生"""print(f"\n🏆 分数 >= {threshold} 的学生:") top_students = list(self.get_top_scorers(threshold))ifnot top_students:print("没有找到高分学生")return# 技巧二:zip - 同时展示排名for rank, (sid, student) inenumerate(top_students, 1):print(f" {rank}. {student.name} - {student.score}分")# 技巧六:集合操作 - 查找学生defsearch_by_name(self, name):"""搜索学生 - 使用集合"""# 找到所有名字包含关键字的学生 results = { sid: student for sid, student inself.students.items() if name in student.name }return results# 技巧八:with语句 - 安全的文件操作defsave_to_file(self, filename="students.txt"):"""保存到文件"""try:withopen(filename, 'w', encoding='utf-8') as f:for sid, student inself.students.items():# 技巧五:f-string 格式化 f.write(f"{sid},{student.name},{student.age},{student.score}\n")print(f"💾 已保存到 {filename}")except Exception as e:print(f"❌ 保存失败: {e}")defload_from_file(self, filename="students.txt"):"""从文件加载"""try:withopen(filename, 'r', encoding='utf-8') as f:# 读取并解析for line in f: line = line.strip()ifnot line:continue parts = line.split(',')iflen(parts) == 4: sid, name, age, score = partsself.students[int(sid)] = Student(name, int(age), float(score))self.next_id = max(self.next_id, int(sid) + 1)print(f"📂 已从 {filename} 加载")except FileNotFoundError:print(f"📁 文件 {filename} 不存在")except Exception as e:print(f"❌ 加载失败: {e}")# 技巧十:异常处理 - 安全的删除操作 @log_operationdefdelete_student(self, student_id):"""删除学生"""try:# 技巧九:isinstance 类型检查ifnotisinstance(student_id, int): student_id = int(student_id)# 技巧四:字典安全访问 student = self.students.get(student_id)if student isNone:print(f"❌ 学号 {student_id} 不存在")returnFalsedelself.students[student_id]print(f"🗑️ 已删除学生: {student.name}")returnTrueexcept ValueError:print("❌ 学号必须是数字")returnFalseexcept Exception as e:print(f"❌ 删除失败: {e}")returnFalse# ==================== 主程序 ====================defmain():"""主程序 - 演示所有功能"""print("=" * 50)print("🎓 学生信息管理系统 v2.0")print("=" * 50)# 创建管理器 manager = StudentManager()# 1. 批量添加学生 - 用列表推导式print("\n【添加学生】") students_data = [ ("小明", 18, 85), ("小红", 19, 92), ("小刚", 20, 78), ("小丽", 18, 95), ("小强", 19, 88), ] manager.add_multiple_students(students_data)# 2. 列出所有学生 - 用enumerateprint("\n【查看学生】") manager.list_students()# 3. 显示高分学生 - 用生成器print("\n【高分学生】") manager.show_top_scorers(85)# 4. 搜索学生 - 用字典推导式print("\n【搜索学生】") results = manager.search_by_name("小")print(f"找到 {len(results)} 个包含'小'的学生:")for sid, s in results.items():print(f" - {s.name}")# 5. 删除学生 - 用异常处理print("\n【删除学生】") manager.delete_student(1) manager.list_students()# 6. 保存和加载 - 用with语句print("\n【文件操作】") manager.save_to_file() manager.load_from_file()print("\n" + "=" * 50)print("🎉 程序结束!")print("=" * 50)if __name__ == "__main__": main()
运行结果
==================================================🎓 学生信息管理系统 v2.0==================================================[操作] 开始执行: add_multiple_students[操作] 完成: add_multiple_students✅ 批量添加了 5 个学生【查看学生】📋 学生列表:--------------------------------------------------1. 学号:1 | 姓名:小明 | 年龄:18 | 分数:85.02. 学号:2 | 姓名:小红 | 年龄:19 | 分数:92.03. 学号:3 | 姓名:小刚 | 年龄:20 | 分数:78.04. 学号:4 | 姓名:小丽 | 年龄:18 | 分数:95.05. 学号:5 | 姓名:小强 | 年龄:19 | 分数:88.0--------------------------------------------------【高分学生】🏆 分数 >= 85 的学生: 1. 小红 - 92.0分 2. 小丽 - 95.0分 3. 小强 - 88.0分 4. 小明 - 85.0分
代码亮点总结
看看我们用到了多少技巧:
⚠️ 常见错误
小甲鱼在这里罗列几个新手最容易犯的错误,看看你中招了没
❌ 错误1:不要在循环里修改列表
# 错误做法!nums = [1, 2, 3, 4, 5]for n in nums:if n % 2 == 0: nums.remove(n)print(nums) # 结果不可预测!# 正确做法:创建新列表nums = [1, 2, 3, 4, 5]nums = [n for n in nums if n % 2 != 0]print(nums) # [1, 3, 5]
❌ 错误2:不要用可变对象作为默认参数
# 错误做法!defadd_item(item, list=[]): # 危险!list.append(item)returnlistprint(add_item(1)) # [1]print(add_item(2)) # [1, 2] - 预期是[2]吧?# 正确做法defadd_item(item, list=None):iflistisNone:list = []list.append(item)returnlist
❌ 错误3:不要滥用列表推导式
# 错误做法!列表推导式不是万能的result = []for i inrange(10):for j inrange(10): result.append(i * j)# 这就不应该用列表推导式,代码反而更难读!# 正确做法:简单的情况用推导式,复杂的情况用普通循环result = [i * j for i inrange(10) for j inrange(10)] # 这个还可以# 但更复杂的逻辑还是用循环吧,别硬凑!
❌ 错误4:不要忘记关闭文件
# 错误做法!f = open('data.txt', 'r')content = f.read()# 如果这里出错,文件永远不会关闭!# 正确做法:永远用with!withopen('data.txt', 'r') as f: content = f.read()# 自动关闭,妥妥的!
❌ 错误5:不要用异常代替流程控制
# 错误做法!try: result = data['key']except KeyError: result = '默认值'# 正确做法:用get()result = data.get('key', '默认值')# 只有在真正"异常"的情况下才用try-except
📌 总结
好啦今天小甲鱼带大家一起学习了10个Python代码优化技巧,让我们来回顾一下:
记住这三点
- 1. 代码首先是给人看的,其次才是给机器跑的——写代码要考虑到以后维护的人(包括你自己)
- 2. 过早优化是万恶之源——先让代码跑起来,再考虑优化,不要为了优化而优化
- 3. 实践出真知——光学不用假把式,一定要动手敲代码!
👋 行动引导
好了,今天的教程就到这里🎉
课后作业
- 1. 练一练:把之前写过的代码,用今天学的技巧重新写一遍
- 2. 想一想:在日常编程中,还有哪些地方可以优化?
- 3. 用一用:下次写Python代码时,试试列表推导式和f-string
互动时间
小伙伴们,你们学废了吗🐟
有什么问题,或者想要小甲鱼讲解什么其他Python知识点,评论区留言告诉我
如果觉得这篇文章对你有帮助,一键三连(点赞、在看、转发)支持一下小甲鱼你们的支持是我创作的最大动力
下期预告:下一期小甲鱼会教大家Python爬虫实战,敬请期待🔍
📢 公众号:Python小甲鱼*🔗 让编程成为一种乐趣*
# 最后的彩蛋!print("感谢阅读!欢迎关注【Python小甲鱼】公众号 🐟")print("一键三连支持一下! 👍❤️📢")