还在 Bug 不断?不妨试试这 2 个装X技巧

本文聚焦Python,为提高程序稳健性,介绍了assert和raise两个异常相关关键字。assert用于断言发现潜在异常,能在多人协作中提供丰富报错信息;raise用于手动触发异常,灵活性稍低。还列举了Python常见异常类型,展示了两关键字的基本用法。

作者 | luanhz

来源 | 小数志(ID:Datazhi)

头图 |  优快云 下载自东方IC

程序员每天遇到 bug 就像喝水吃饭一样稀松平常,关键在于怎么高效而不失优雅的面对这些 bug!所以,你还在固执的使用 try……except 吗?

为了提高程序运行的稳健性,几乎所有语言都提供了 try……except……用法, Python 也不例外。虽然 try……except……语法能够确保程序能够跳过异常代码片段,无论如何都继续执行下去,但有时主动的触发报错和异常也是一种行之有效的程序员装X护体方法。

本文主要介绍 Python 中的两个异常相关的关键字:assert 和 raise,前者用于断言发现潜在异常,后者用于触发报错,实际上二者功能有很大相近之处。

Python异常分类

Python内置了数十种Exception/Error类型,例如常见的如下几种:

  • IndexError,索引错误,例如引用了超出列表长度的索引

  • KeyError,键值错误,例如引用了字典中不存在的键值

  • NameError,未声明错误,例如引用了未赋值的对象或变量

  • SyntaxError,语法错误,广泛存在

  • IndentationError,缩进错误,这是Python摒弃花括号而用缩进区分代码段的特色产物

  • TypeError,类型错误,例如执行数字和字符串相加会引发此类错误

这些错误很常见,也比较直观易懂。但有没有考虑过主动触发这些错误呢?

assert:断言

assert 一般用于函数和类的内部,在执行具体逻辑前首先对输入参数和程序执行状态进行一定的检查和预判,仅当执行状态满足时才继续执行后续的逻辑,否则断言条件不满足,引发后续的提示。

assert 关键字基本用法为:

assert "条件判断", "条件不满足时输出的提示信息"

例如,设计一个两数相除的函数,那么应当在执行相除前检查:

  1. 两个输入参数是否为数值型

  2. 除数是否不为0

这一条件判断可用assert完成,并在条件不满足时优雅的提示报错:

 def div(x, y):
     assert isinstance(x, (float, int)) and isinstance(y, (float, int)), \
                 "param `x` and `y` expected to be 'int' or 'float' type"
     assert y != 0, "param `y` should not to be exactly `0`"
     return x/y
 
 div(1, "2")
 ---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-206-579e0bede4d8> in <module>
----> 1 div(1, "2")
<ipython-input-205-258ec937e818> in div(x, y)
      1 def div(x, y):
      2     assert isinstance(x, (float, int)) and isinstance(y, (float, int)), \
----> 3                 "param `x` and `y` expected to be 'int' or 'float' type"
      4     assert y != 0, "param `y` should not to be exactly `0`"
      5     return x/y
AssertionError: param `x` and `y` expected to be 'int' or 'float' type

由于输入参数y是字符串类型,断言失败,引发断言错误

相较于 try……except……用法,assert 的最大意义在于能够及时发现程序中未按预期状态执行的错误,这在多人协作 coding 过程中,比 except 更能提供丰富的报错信息。

raise:触发异常

实际上,raise 关键字的哲学与 assert 是有相通之处的,只不过 assert 包含逻辑判断和触发提示信息两部分内容,而 raise 则只用于手动触发异常,且一般触发的是 Python 内置异常类型。某种程度上,raise 的灵活性要比 assert 低,在个人实际使用过程中也几乎很少用到。

raise关键字基本语法为:

raise 异常类名称(描述信息)

例如,仍以实现上述 div 函数功能为例,以 raise 关键字执行同样的断言功能,则可如下实现:

def div(x, y):
    if not isinstance(x, (float, int)) or not isinstance(y, (float, int)):
        raise TypeError("param `x` and `y` expected to be 'int' or 'float' type")
    if y == 0:
        raise ZeroDivisionError("param `y` should not to be exactly `0`")
    return x/y


div(1, 0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-213-4267cdef819f> in <module>
----> 1 div(1, 0)
<ipython-input-212-dce337c4d91a> in div(x, y)
      3         raise TypeError("param `x` and `y` expected to be 'int' or 'float' type")
      4     if y == 0:
----> 5         raise ZeroDivisionError("param `y` should not to be exactly `0`")
      6     return x/y


ZeroDivisionError: param `y` should not to be exactly `0`

由于除数为0,raise关键字触发异常

以上就是 Python 中这两个关键字的简单用法,单论其实质功能而言都称不上是不可或缺,甚至可能会觉得有些鸡肋,但不得不说在某些场景下二者其实都还是有用武之地,或许届时你的代码也可以如大佬一般:优雅高效,同时略显装X!


福 利优快云旗下公众号全新搜索技能上线啦!只要在公众号内回复消息就能自动回复想搜索的内容啦!现在体验有惊喜,每日参与搜索打卡,连续打卡满3天、7天、14天均有优快云精美礼品相送 百分百有礼!快戳每日体验优快云公众号搜索功能打卡


更多精彩推荐
☞倪光南、求伯君“出山”:爱解 Bug、无惧“35岁魔咒”、编码之路痛并快乐!

☞饿了么技术往事
☞我坦白!我是第五位飞上太空的程序员游客

☞赠书 | 图像分类问题建模方案探索实践

☞大神们都是如何在时间序列中进行特征提取的?看完就懂了!
☞Value DeFi遭黑客攻击始末,闪电贷这次又带走了700万美元
点分享点点赞点在看
<think>嗯,用户问为什么在Keil里设置断点后运行程序没有到达断点的位置。这个问题可能有多种原因,需要一步步排查。首先,我得回忆一下Keil调试的基本流程和常见问题。 首先,断点是否真的设置成功了?有时候用户可能误操作,比如点击了行号旁边但没有出现红色的断点标记。这时候需要检查断点是否确实存在。如果断点图标显示灰色,可能表示该行代码无法设置断点,比如在空行或注释行。这是常见的问题之一。 然后,程序有没有编译成功并且正确下载到目标设备?如果编译有错误或者下载失败,程序可能还在运行旧版本的代码,这时候断点的位置可能已经改变或者不存在。需要确认编译输出窗口没有报错,并且下载过程顺利完成。 接下来,优化设置可能会影响断点的行为。如果编译器优化级别过高,比如设置为-O3,某些代码可能会被优化掉,导致断点无法触发。这时候建议将优化级别调低,比如改为-O0,重新编译后再试。同时,检查代码是否被优化,比如某些变量被优化掉,也可能导致断点位置不可达。 然后考虑代码执行流程是否真的会经过断点位置。比如,有没有条件判断或循环导致代码跳过了断点所在的行。例如,断点设置在if语句内部,但条件不满足,导致无法执行到那里。这时候需要检查代码逻辑,或者使用单步调试跟踪程序流程。 还有可能是硬件问题,比如看门狗定时器没有禁用,导致程序在断点触发前就复位了。或者调试器连接不稳定,导致断点没有被正确设置。这时候需要检查硬件连接,确认目标板供电正常,调试接口接触良好。 另外,调试配置是否正确也很重要。比如,是否选择了正确的调试器型号,比如ST-Link还是J-Link,配置是否正确。有时候时钟频率设置过高可能导致调试不稳定,适当降低时钟频率试试。 还有可能断点设置在初始化代码之前,比如在main函数之前,而程序在启动时卡在某个地方,比如时钟配置错误,导致根本执行不到main函数。这时候需要检查启动文件,或者单步执行到main函数看看是否卡在初始化阶段。 此外,某些断点类型可能有限制,比如硬件断点数量有限,如果设置的断点超过硬件支持的数量,后面的断点可能不会生效。需要确认使用的调试器支持的硬件断点数量,或者尝试改用软件断点。 最后,可能是Keil软件本身的bug或者配置问题,尝试重启Keil,或者重新安调试器驱动,更新到最新版本的Keil看看问题是否解决。 总结下来,可能的排查步骤包括:确认断点设置正确、检查编译和下载是否成功、调整优化级别、检查代码执行路径、验证硬件连接和配置、查看调试器设置、处理看门狗或复位问题、确认断点数量限制等。需要一步步排除可能的原因,逐步缩小问题范围。</think>### **一、断点未被触发的常见原因及解决方案** --- #### **1. 断点设置问题** - **现象**:断点图标显示为空心或灰色 - **原因**: - 断点设置在**非执行代码行**(如注释、空行、宏定义) - Keil版本对Cortex-M内核断点数量有限制(如Cortex-M3硬件断点仅支持6个) - **解决方法**: 1. 检查代码行左侧是否出现**红色实心圆点** 2. 删除冗余断点,使用`Debug -> Breakpoints`窗口管理 --- #### **2. 程序未执行到断点位置** - **逻辑路径问题** - **案例**: ```c if (x > 100) { // 断点设置在内部 y = x * 2; // 若x始终≤100,断点不会被触发 } ``` - **验证方法**: - 使用`Step Into (F11)`逐语句跟踪执行流程 - **中断干扰** - **现象**:高优先级中断持续抢占CPU - **调试技巧**: - 在中断服务程序(ISR)中设置断点 - 检查NVIC优先级配置 --- #### **3. 编译器优化导致代码被跳过** - **关键影响**: - 优化级别`-O2`或更高可能**删除未使用的变量** - 循环展开(Loop Unrolling)改变代码结构 - **实验验证**: 1. 修改优化级别为`-O0`(Project → Options → C/C++ → Optimization Level) 2. 对比反汇编视图(`Debug → View Disassembly`) --- #### **4. 硬件/调试器配置错误** - **调试接口异常** - **典型表现**: - 调试器提示"Connection reset" - 程序计数器(PC)值显示为`0xFFFFFFFF` - **排查步骤**: 1. 检查SWD/JTAG接口连线(确保`SWCLK`和`SWDIO`正确连接) 2. 重启目标板并重插调试器 - **时钟配置错误** - **案例**:STM32CubeMX生成的时钟树未生效,导致CPU未运行 - **验证方法**: ```c SystemCoreClockUpdate(); // 更新时钟变量 printf("SYSCLK: %d Hz\n", SystemCoreClock); // 输出实际时钟 ``` --- ### **二、进阶调试技巧** --- #### **1. 实时监控程序流** - **使用`Call Stack + Locals`窗口** - 查看函数调用链(需在Options → Debug → Settings中启用`Call Stack`) - 监控局部变量实时值 - **内存断点(Data Breakpoint)** - 设置条件:当特定内存地址被写入时暂停 - 操作路径:`Debug → Breakpoints → Memory` --- #### **2. 诊断复位问题** - **看门狗触发复位** - **现象**:程序在断点前反复重启 - **解决方法**: ```c IWDG->KR = 0xAAAA; // 在main循环中定期喂狗 // 或临时禁用看门狗 ``` - **电源噪声导致复位** - **排查工具**: - 示波器测量电源轨纹波(需<50mV) - 在复位引脚(NRST)添加0.1μF电容 --- ### **三、Keil特定问题处理** --- #### **1. 工程配置错误** - **链接脚本(Scatter File)问题** - **表现**:代码未加载到正确地址 - **检查方法**: ```armasm LDR R0, =__main // 查看启动文件跳转地址 ``` - **Flash算法不匹配** - **典型错误**: `Error: Flash Download failed - Target DLL has been cancelled` - **修复步骤**: 1. 在`Flash → Configure Flash Tools`中选择正确的算法 2. 更新Device Family Pack(DFP) --- #### **2. 调试器驱动冲突** - **ST-Link/V2固件升级** - **操作流程**: 1. 连接ST-Link到PC 2. 运行`ST-Link Upgrade`工具 3. 点击`Device Connect`并升级 - **J-Link接口模式切换** - 对于SWD模式: ```powershell JLink.exe -if SWD -speed 4000 ``` --- ### **四、快速验证流程** 1. **基础检查** - 确认断点为红色实心状态 - 检查`Build Output`窗口无编译错误 2. **单步执行测试** - 在`main()`入口设置断点,执行`Run (F5)` - 若无法暂停,说明调试器未连接成功 3. **反汇编验证** - 按`Ctrl+F11`打开反汇编窗口 - 观察PC指针是否在预期地址 4. **硬件信号测量** - 使用示波器检查: - CPU时钟信号(如HSE输出) - 调试接口(SWCLK波形应为方波) --- **总结**:Keil断点失效的90%问题可通过**降低优化级别**、**检查硬件连接**和**验证代码逻辑**解决。若仍存在问题,需结合反汇编分析与实时调试工具深入诊断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值