百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

VBA宏总崩溃?Python脚本老闪退?这招让你的代码从此“抗摔”!

off999 2025-09-01 11:26 20 浏览 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道题测测你的错误处理水平

  1. VBA中,用于跳转到错误处理代码块的关键字是? A. On Error Resume Next B. On Error GoTo C. Exit Sub D. Err.Clear
  2. Python中,若要捕获“文件未找到”错误,应使用哪个异常类? A. TypeError B. ValueError C. FileNotFoundError D. ZeroDivisionError
  3. 以下哪项是错误处理的核心目的? A. 让代码永远不报错 B. 让程序崩溃时更美观 C. 在出错时优雅应对,减少损失 D. 提高代码运行速度

【答案】

  1. B(On Error GoTo用于跳转到错误处理标签)
  2. C(FileNotFoundError专门捕获文件未找到错误)
  3. C(错误处理的目的是在出错时减少损失,而非完全避免错误)



欢迎关注:千万别学excel,这里有数千篇excel相关视频和文章,带你玩转excel!祝你早日升任CEO,迎娶白富美,走上人生巅峰~( ̄▽ ̄~)~

相关推荐

u盘在电脑上怎么找出来(u盘在电脑上怎么找到)

在电脑中找不到u盘,是因为系统没有自动识别出来,手动打开即可,具体的解决步骤如下:1、在桌面上点击我的电脑,右键,管理。2、打开管理界面,点击储存。3、进到储存页面。4、到这一步,也就可以看到了,有这...

联想一体机怎么进入bios(联想一体机怎么进入u盘启动)

所需工具:联想Lenovo品牌一体机、启动U盘。具体步骤如下:1、联想一体机从U盘启动设置步骤如下重启联想一体机,启动过程中按F1进入BIOS,部分机型则是开机按Enter键,进入之后再按F12选择进...

如何装ghost系统盘(ghost装机教程)

ghost是不能做系统c盘,它是一种对硬盘和分区制作成映像文件进行备份和恢复的工具软件,是不能进行操作系统安装。这个软件的使用目的是,当我们安装配置好操作系统以后,用ghost软件对c盘进行备份,或者...

加密u盘如何格式化(加密u盘如何格式化手机)

1,点击系统与安全进入电脑的控制面板界面,点击上方的系统与安全的选项,在系统界面找到最下方的管理工具功能组。2,选中u盘选择管理工具下面的创建并格式化硬盘分区,点击弹出磁盘管理的界面,在这个里面选中你...

万能显卡驱动离线版pc(万能显卡驱动离线版)

万用驱动是综合各电脑硬件的性能而制做的软件,对于大多数的电脑硬件驱动都好用,但对于少数品牌电脑驱动要求严格的,就不灵了。有的硬件用万能驱动后,使用效果不佳,就是因为没有完全驱动好。所以,知名品牌电脑硬...

如何让电脑一键还原(电脑怎样才能一键还原)
  • 如何让电脑一键还原(电脑怎样才能一键还原)
  • 如何让电脑一键还原(电脑怎样才能一键还原)
  • 如何让电脑一键还原(电脑怎样才能一键还原)
  • 如何让电脑一键还原(电脑怎样才能一键还原)
笔记本windows8系统下载(笔记本电脑系统win8)

在电脑上面就可以下载,打开浏览器搜索windous8系统会出现一些下拉选择,选择第一条或者选择有官网字样的,就直接有下载按钮,然后点击下载就可以了win8可以支持现在可以见到的所有Photosho...

win 11(win 11 25h2)

 Windows11是由微软公司(Microsoft)开发的操作系统,应用于计算机和平板电脑等设备。于2021年6月24日发布,2021年10月5日发行。Windows11提供了许多创新...

手机视频恢复软件免费版下载

手机视频删了怎么恢复  一、安卓手机视频恢复  1.打开电脑,移动鼠标,进入互盾安卓恢复大师官网,下载并安装该软件。手机连接至电脑。手机视频删了怎么恢复  2.打开运行互盾安卓恢复大师,在软件界面看到...

diy电脑装机教程(diy电脑组装步骤)

1,看价格。根据自己的预算价格,选择适合该价格的电脑。注意不要以过高的价格买到配置过低的电脑;2,看性能。根据自己需要的电脑性能,以合理的价格购买。注意不要以过高的价格买到配置过低的电脑。电脑的配置如...

u盘莫名其妙要格式化(u盘总是要格式化什么意思)

如果您在使用U盘时突然收到提示需要格式化的消息,这可能是由于以下原因之一引起的:U盘感染病毒:U盘中可能存在恶意病毒,这些病毒可能会导致U盘无法正常使用。当您尝试打开U盘时,系统会提示您进行格式化操作...

win7家庭版原版(win7家庭版价格)

你的win7旗舰版应该是个盗版软件,在你使用的过程中你可能触碰到了后台升级,升级完以后就变成了家庭版了,在你不知不觉中被改变的,厄这个软件属于盗版的,厄升级完以后没什么大区别,这个旗舰版家庭版在家里面...

win10自动更新失败怎么办(win10自动升级失败)

安装更新失败有许多原因。WindowsUpdate需要能够扫描您的计算机以了解需要哪些更新,并能够下载和安装这些更新。如果某个阶段遇到问题,则可能阻止某个更新安装到计算机中。有关错误或失败的详细信...

截图的几种方法(截图的几种方法有哪些)

 第一种截图方式:按printScreen键。按一下键盘上的printScreen键以后,整个屏幕会被截取下来,截图会默认保存在剪贴板中。第二种截图方式:使用微信截图。进入聊天界面,我们会发...

电脑装了两个系统怎么切换(电脑安装2个系统怎么更换启动)

1.点击运行打开电脑点击左下角的开始菜单栏选项,右击鼠标在序列栏中选择运行打开。2.输入msconfig接着在运行的输入框中输入msconfig点击确定即可打开系统配置。3.点击引导打开系统配置的页面...

取消回复欢迎 发表评论: