VBA宏总崩溃?Python脚本老闪退?这招让你的代码从此“抗摔”!
off999 2025-09-01 11:26 29 浏览 0 评论
导语:
上周有个读者急吼吼地私信我:“老师,我写了个VBA宏整理半年数据,结果跑到第800行的时候弹出个Error 1004,前功尽弃!有没有办法让宏‘抗摔’?”还有位Python新手更崩溃:“明明写了检查空值的代码,结果因为一个单元格是文本格式,整个脚本直接闪退,半小时白干……”
别慌!这不是你技术菜,而是没掌握编程圈的“保命神技”——错误处理。今天第五讲,我用20年编程经验总结的“防崩指南”,手把手教你让VBA和Python代码从“玻璃心”变“金刚不坏”,从此告别“改不完的bug,流不完的眼泪”!
第五讲:错误处理——让代码“稳如老狗”的终极法则
程序员圈有句扎心真相:“完美的代码不存在,但能优雅处理错误的代码才专业。” 无论是VBA还是Python,错误处理不是“加分项”,而是“生存线”。它能让你在用户骂“这破程序又崩了”时,淡定地说:“我早料到了。”
第一部分:VBA——用“安全网”兜住所有意外
VBA的错误处理逻辑像极了“老司机的应急反应”:预判可能翻车的点,提前铺好安全网,出事了就顺着网爬回安全区。 它的核心工具是On Error语句,这是VBA程序员的“保命符”。
1. 必杀技:On Error GoTo——精准跳转错误处理区
这是VBA最经典的错误捕获模式,相当于给代码装了个“GPS导航”:主逻辑跑着跑着出错了?立刻跳转到指定标签的“急救站”处理。
Sub 批量计算佣金()
' 1. 启动“安全模式”:一旦出错,跳转到ErrorHandler标签
On Error GoTo ErrorHandler
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("数据源") ' 可能出错点1:工作表不存在
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row ' 可能出错点2:A列全空
Dim i As Long, sales As Double, commission As Double
For i = 2 To lastRow
sales = ws.Cells(i, "A").Value
If sales < 0 Then
Err.Raise vbObjectError + 999, , "销售额不能为负!" ' 主动抛错(自定义错误)
End If
commission = sales * 0.1 ' 可能出错点3:sales是文本格式(类型错误)
ws.Cells(i, "B").Value = commission
Next i
MsgBox "计算完成!", vbInformation
Exit Sub ' 正常结束,跳过错误处理区
' 2. 错误处理区(急救站)
ErrorHandler:
' 显示具体错误信息(错误号+描述+来源)
MsgBox "错误号:" & Err.Number & vbCrLf & _
"错误原因:" & Err.Description & vbCrLf & _
"错误来源:" & Err.Source, vbCritical, "程序异常"
' 可选操作:记录错误日志(写入文本文件)
Open ThisWorkbook.Path & "\错误日志.txt" For Append As #1
Print #1, "[" & Now() & "] 错误号:" & Err.Number & ";描述:" & Err.Description
Close #1
' 清除错误状态,避免影响后续代码
Err.Clear
End Sub
这段代码能处理哪些崩溃?
- 如果“数据源”工作表被删除,触发错误号9:下标越界,跳转到处理区并记录日志;
- 如果A列全是空值,lastRow会是1,循环从2到1不执行,但不会报错;
- 如果A列有文本(如“无效数据”),sales = ws.Cells(i, "A").Value会触发错误号13:类型不匹配,同样被捕获;
- 主动用Err.Raise抛出的自定义错误(如销售额为负),也会被精准捕获。
2. 进阶技巧:On Error Resume Next——小心使用的“免死金牌”
这条语句的意思是:“出错了?别管,继续执行下一句。” 它适合处理“无关痛痒”的小错误(比如删除一个不存在的文件),但新手慎用——用不好会让程序“带病运行”,埋下更大隐患。
Sub 清理临时文件()
On Error Resume Next ' 开启“免死金牌”
Kill "C:\Temp\old_report.xlsx" ' 文件不存在?忽略错误
Kill "D:\Backup\temp.xls" ' 路径错误?也忽略
On Error GoTo 0 ' 关闭“免死金牌”,恢复严格错误提示
MsgBox "临时文件清理完成(可能有遗漏)", vbInformation
End Sub
VBA错误处理哲学: 像老司机开车——提前检查路况(预判错误点),出事故立刻靠边停车(跳转处理区),修好后继续上路(清除错误状态)。
第二部分:Python——用“精密陷阱”捕获所有异常
Python的错误处理更像“工程师设计精密仪器”:提前预判所有可能的故障点,为每种故障定制“专属陷阱”,程序跑着跑着出错了?陷阱自动触发,稳稳接住! 它的核心是
try...except...else...finally结构,这是Python程序员的“防崩秘籍”。
1. 四大利器:
try...except...else...finally
- try:放可能出错的“危险代码”;
- except:针对不同错误类型(如除零、文件不存在)定制陷阱;
- else:如果try里的代码没出错,执行这里的“成功逻辑”;
- finally:无论是否出错,最后一定要执行的“收尾动作”(如关闭文件、释放资源)。
import xlwings as xw
import logging # 导入日志模块,专业记录错误
# 配置日志:将错误写入文件(比弹窗更专业)
logging.basicConfig(filename='error.log', level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s')
def 计算佣金(sales):
try:
# 危险操作1:读取Excel单元格(可能为空、非数值)
if sales < 0:
raise ValueError("销售额不能为负数!") # 主动抛自定义异常
return sales * 0.1
except ZeroDivisionError:
logging.error("除零错误:销售额为0,无法计算佣金")
return 0
except TypeError as e:
logging.error(f"类型错误:输入应为数值,实际是{type(sales)},错误详情:{e}")
return None
except ValueError as e:
logging.error(f"自定义错误:{e}")
return None
except Exception as e: # 兜底陷阱,捕获所有未预期的错误
logging.error(f"未知错误:{e}", exc_info=True) # 记录完整堆栈信息
return None
else:
logging.info("佣金计算成功") # 仅当无错误时执行
finally:
print("佣金计算流程结束(无论成功与否)") # 必执行的收尾动作
# 主程序:循环处理数据
def 批量处理():
try:
wb = xw.books.open("销售数据.xlsx") # 危险操作2:打开不存在的文件
sheet = wb.sheets["数据"]
last_row = sheet.range("A" + str(sheet.cells.last_cell.row)).end("up").row
for row in range(2, last_row + 1):
sales = sheet.range(f"A{row}").value
commission = 计算佣金(sales)
sheet.range(f"B{row}").value = commission
except FileNotFoundError:
logging.critical("文件未找到:请检查'sales数据.xlsx'路径是否正确")
except PermissionError:
logging.critical("权限不足:请关闭Excel文件后重试")
except Exception as e:
logging.critical(f"批量处理失败:{e}", exc_info=True)
finally:
try:
wb.close() # 无论是否出错,尝试关闭工作簿
except:
pass # 如果wb未成功打开,忽略此错误
批量处理()
这段代码有多“抗造”?
- 文件不存在?触发FileNotFoundError,记录日志并提示;
- 权限不足?触发PermissionError,避免程序崩溃;
- 销售额是文本?触发TypeError,记录类型错误详情;
- 销售额为负?触发自定义ValueError,明确提示原因;
- 所有操作结束后,无论成功与否,finally都会尝试关闭工作簿,防止资源泄露。
2. 高手进阶:自定义异常类——让错误“更懂你”
Python允许你自定义异常类型,让错误信息更贴合业务场景。比如电商系统中,定义库存不足异常、支付超时异常,代码会更清晰。
class 库存不足异常(Exception):
"""当商品库存小于订单数量时抛出的异常"""
def __init__(self, 商品名称, 当前库存, 订单数量):
self.商品名称 = 商品名称
self.当前库存 = 当前库存
self.订单数量 = 订单数量
super().__init__(f"{商品名称}库存不足!当前库存{当前库存},订单需要{订单数量}")
# 使用自定义异常
def 下单(商品名称, 当前库存, 订单数量):
if 订单数量 > 当前库存:
raise 库存不足异常(商品名称, 当前库存, 订单数量)
print("下单成功!")
# 测试
try:
下单("手机", 10, 15)
except 库存不足异常 as e:
print(f"下单失败:{e}") # 输出:下单失败:手机库存不足!当前库存10,订单需要15
Python错误处理哲学: 像工程师设计电路——每个可能的故障点都有对应的保险丝(except),主电路(try)负责正常工作,保险丝熔断(捕获错误)时启动备用方案(处理逻辑),最后无论是否熔断都要切断总电源(finally)。
核心实战:用错误处理“复活”崩溃脚本
场景: 你需要写一个脚本,从Excel读取员工绩效分,计算奖金(绩效分×1000),并将结果写入新工作表。但实际数据中可能存在:
- 绩效分是文本(如“优秀”);
- 绩效分超过100(系统限制最高100);
- 目标工作表已存在(需先删除旧表)。
VBA“防崩版”解法:
Sub 生成奖金表()
On Error GoTo ErrorHandler
Dim wsSource As Worksheet, wsTarget As Worksheet
Set wsSource = ThisWorkbook.Sheets("绩效数据")
Dim lastRow As Long: lastRow = wsSource.Cells(wsSource.Rows.Count, "A").End(xlUp).Row
' 检查目标表是否存在,存在则删除(可能出错点:工作表被保护)
On Error Resume Next
Application.DisplayAlerts = False ' 关闭删除确认弹窗
ThisWorkbook.Sheets("奖金表").Delete
Application.DisplayAlerts = True
On Error GoTo ErrorHandler
' 创建新目标表
Set wsTarget = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
wsTarget.Name = "奖金表"
wsTarget.Range("A1:B1").Value = Array("姓名", "奖金")
' 计算奖金
For i = 2 To lastRow
Dim 姓名 As String, 绩效分 As Double, 奖金 As Double
姓名 = wsSource.Cells(i, "A").Value
绩效分 = wsSource.Cells(i, "B").Value
' 检查绩效分是否为数值
If Not IsNumeric(绩效分) Then
Err.Raise vbObjectError + 100, , "绩效分必须为数值!"
End If
' 检查绩效分是否超上限
If 绩效分 > 100 Then
Err.Raise vbObjectError + 101, , "绩效分不能超过100!"
End If
奖金 = 绩效分 * 1000
wsTarget.Cells(i, "A").Value = 姓名
wsTarget.Cells(i, "B").Value = 奖金
Next i
MsgBox "奖金表生成成功!", vbInformation
Exit Sub
ErrorHandler:
MsgBox "错误:" & Err.Description & vbCrLf & "请联系管理员。", vbCritical
' 记录日志(同上,此处省略)
Err.Clear
End Sub
Python“防崩版”解法:
import xlwings as xw
import logging
logging.basicConfig(filename='奖金表错误.log', level=logging.ERROR)
def 生成奖金表():
try:
wb = xw.books.open("绩效数据.xlsx")
ws_source = wb.sheets["绩效数据"]
last_row = ws_source.range("A" + str(ws_source.cells.last_cell.row)).end("up").row
# 删除已存在的奖金表(可能出错点:表被保护/不存在)
try:
wb.sheets["奖金表"].delete()
except:
pass # 表不存在时忽略
# 创建新奖金表
ws_target = wb.sheets.add("奖金表")
ws_target.range("A1:B1").value = ["姓名", "奖金"]
# 计算奖金
for row in range(2, last_row + 1):
姓名 = ws_source.range(f"A{row}").value
绩效分 = ws_source.range(f"B{row}").value
# 检查绩效分是否为数值
if not isinstance(绩效分, (int, float)):
raise TypeError(f"第{row}行绩效分非数值:{绩效分}")
# 检查绩效分是否超上限
if 绩效分 > 100:
raise ValueError(f"第{row}行绩效分超上限:{绩效分}")
ws_target.range(f"A{row}").value = 姓名
ws_target.range(f"B{row}").value = 绩效分 * 1000
wb.save("奖金表.xlsx")
wb.close()
print("奖金表生成成功!")
except FileNotFoundError:
logging.error("绩效数据.xlsx未找到,请检查路径")
except PermissionError:
logging.error("文件被占用,请关闭后重试")
except (TypeError, ValueError) as e:
logging.error(f"数据错误:{e}")
except Exception as e:
logging.error(f"未知错误:{e}", exc_info=True)
finally:
try:
wb.close() # 确保关闭工作簿
except:
pass
生成奖金表()
终极对比:VBA与Python的错误处理谁更强?
特性 | VBA | Python |
错误捕获方式 | On Error GoTo跳转 | try...except精准捕获 |
错误类型支持 | 仅内置错误号(如Error 1004) | 支持自定义异常类,类型更灵活 |
日志记录 | 需手动写文件(麻烦) | 内置logging模块(专业) |
代码可读性 | 错误处理与业务逻辑混杂(易乱) | 异常块独立(结构清晰) |
适用场景 | 小范围、单一功能的Excel宏 | 复杂系统、需要多人协作的脚本 |
比喻 | 老司机的“应急工具箱” | 工程师的“精密故障排查系统” |
千万别学Excel结语:错误处理,是程序员的“职业尊严”
从今天起,请记住:
- 写VBA时,每个Sub和Function的第一行都加上On Error GoTo,别让崩溃成为习惯;
- 写Python时,每个try块都明确列出可能出现的异常类型,别让“万能except”毁了代码的可维护性;
- 无论用什么语言,日志记录都是你的“后悔药”——出错了没关系,但至少要知道怎么错的。
最后送你一句话: 用户不会因为你处理了错误而夸你,但一定会因为你没处理错误而骂你。而专业的程序员,连“被骂的机会”都不给自己。
互动话题: 你在写代码时遇到过最离谱的崩溃是什么?是因为单元格格式错了?还是文件被同事误删了?在评论区分享你的“血泪史”!
Excel #Python #VBA #错误处理 #编程技巧 #办公自动化 #代码健壮性
【测试题】3道题测测你的错误处理水平
- VBA中,用于跳转到错误处理代码块的关键字是? A. On Error Resume Next B. On Error GoTo C. Exit Sub D. Err.Clear
- Python中,若要捕获“文件未找到”错误,应使用哪个异常类? A. TypeError B. ValueError C. FileNotFoundError D. ZeroDivisionError
- 以下哪项是错误处理的核心目的? A. 让代码永远不报错 B. 让程序崩溃时更美观 C. 在出错时优雅应对,减少损失 D. 提高代码运行速度
【答案】
- B(On Error GoTo用于跳转到错误处理标签)
- C(FileNotFoundError专门捕获文件未找到错误)
- C(错误处理的目的是在出错时减少损失,而非完全避免错误)
欢迎关注:千万别学excel,这里有数千篇excel相关视频和文章,带你玩转excel!祝你早日升任CEO,迎娶白富美,走上人生巅峰~( ̄▽ ̄~)~
相关推荐
-
- qq恢复删除好友官网(qq恢复已删好友)
-
qq恢复官方网站,http://huifu.qq.com/1、什么是QQ恢复系统?QQ恢复系统是腾讯公司提供的一项找回QQ联系人、QQ群的服务,向所有QQ用户免费开放。2、QQ恢复系统能恢复多长时间内删除的好友?普通用户可以申请恢复3个月内...
-
2025-12-28 16:03 off999
- 优启通u盘重装win7系统教程(优启通u盘装win7系统教程图解)
-
系统显示未找到万能驱动的解决方法是:1、重插下usb口1、造成“找不到驱动器设备驱动程序”的原因,可能是usb口出现问题。2、换个usb口可能是单独这个usb口出现问题,可以选择另外的usb口重试wi...
- wifi加密方式怎么设置(wifi网络加密怎么设置)
-
若你想将自己的无线网改成加密的,可以按照以下步骤操作:1.打开你的路由器管理界面。一般来说,在浏览器地址栏输入“192.168.1.1”或“192.168.0.1”,然后输入用户名和密码登录就可以打...
- sql数据库自学(数据库入门必看——《sql基础教程》)
-
SQLServer数据库基础知识:1.数据库是由数据组成的,这些数据可以被组织成有序的数据结构,以支持特定的应用程序。2.数据库管理系统(DBMS)是一种软件工具,用于创建、管理和操作数据库。...
- 无线网连接不可上网怎么回事
-
可能有几下几方面原因:1、无线路由器网络参数设置错误,无法拨通ISP运营商的局端设备,无法接入互联网;2、宽带线路出现故障,路由器无法拨通ISP运营商的局端设备,无法连通;3、宽带DNS服务器由于某种...
- 恢复大师app下载(恢复大师app下载软件)
-
是真的。开心手机恢复大师是一款苹果手机数据恢复软件,可以恢复删除的微信聊天记录、短信、通讯录、备忘录、qq聊天记录等17种数据。我测试了一下,确实是可以恢复的。而且开心手机恢复大师是可以免费试用的,是...
- windowsxp下载网站(windows xp download)
-
目前无法下载因为红色警戒XP电脑版是一款已经停止开发的游戏,官方已经停止了对其的支持和更新。虽然网上有一些模拟器可以运行该游戏,但是安装和使用相对困难,而且可能存在版权问题。建议玩家选择其他同类型的游...
- 没人用过的激活码没过期(没人用过的激活码没过期可以用吗)
-
迷你世界并不存在什么激活码的。《迷你世界》是一款高度自由的休闲类3D沙盒游戏,有着非常方便快捷的多人联机模式,只要有网络就能和各个地方的小伙伴们一起玩。这里没有等级和规则限制,没有规定的玩法,只有随心...
- 2017年联想笔记本电脑有几款
-
17年的笔记本电脑可以勉强安装一下win10系统试试。关键看你的内存有多少,内存大于4个G的话可以安装win10速度不会太慢。最好是安装win7系统,这样能发挥你这台电脑的所有的性能,你用起来也会感觉...
- 当前显卡排名(当下显卡排行)
-
101、Irispro5802、Iris62002、Iris52004、UHD630/6205、HD6306、HD5307、HD46008、HD44009、HD420010、HD40...
- win10专业版激活变成企业版(win10专业版激活变成企业版怎么办)
-
win10永久激活密钥很少,一旦网上有分享,等你拿到时就超过期限了,一般是要购买。激活win10系统可以使用激活工具:win10激活工具下载一、win10专业版产品密钥NXRQM-CXV6P-PBGV...
- ghostwinxp下载纯净版(ghost win7纯净版下载)
-
可以下载的,现在官网和其他网站上都可以下载xp原版的。可以通过以下步骤下载我的世界游戏到xp系统中:1.首先打开你的浏览器软件,搜索关键字“我的世界xp版下载”,找到可靠下载地址;2.从下载页面下...
- 惠普完整版驱动(惠普最新驱动)
-
惠普官方的标准操作:HP1050安装驱动步骤:一:准备:拿出驱动光盘放入光驱或到HP官网下载完整版驱动。二:不要插USB数据线或插上线打印机电源不要开,安装完整版驱动,当程序提示插入USB数据线时,插...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
系统u盘安装(win11系统u盘安装)
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
