不推荐用 try 代替 if 判断键或属性存在,应优先使用 dict.get() 或 hasattr();valueerror 适合参数校验失败;异常替代返回码需依场景而定;自定义异常应继承 exception。

用 try 代替 if 判断是否存在键或属性?
不推荐。Python 的 KeyError 和 AttributeError 确实能“绕过”显式检查,但这是拿异常机制干查询的活——语义错位,且在可预期的分支场景下性能更差。
常见错误现象:try/except 块里只做一次属性访问,却捕获宽泛的 Exception,掩盖了真正的逻辑错误;或者反复触发异常来“试探”数据结构,导致 CPU 时间浪费在栈展开上。
- 优先用
dict.get(key, default)或hasattr(obj, "attr"),它们是 O(1)、无副作用、意图清晰 - 若必须用异常(比如第三方库返回结构不确定),只捕获具体异常类型,如
KeyError,绝不用裸except: - CPython 中,抛出并捕获异常的开销约是普通分支的 10–100 倍,尤其在循环内要警惕
ValueError 能否用于参数校验失败?
可以,而且是标准做法。Python 内置函数(如 int()、json.loads())大量使用 ValueError 表示输入格式或语义错误,符合约定。
使用场景:函数契约明确但输入越界,比如要求传入正整数,结果给了负数或字符串 "abc"。
立即学习“Python免费学习笔记(深入)”;
系统简介:冰兔BToo网店系统采用高端技术架构,具备超强负载能力,极速数据处理能力、高效灵活、安全稳定;模板设计制作简单、灵活、多元;系统功能十分全面,商品、会员、订单管理功能异常丰富。秒杀、团购、优惠、现金、卡券、打折等促销模式十分全面;更为人性化的商品订单管理,融合了多种控制和独特地管理机制;两大模块无限级别的会员管理系统结合积分机制、实现有效的推广获得更多的盈利!本次更新说明:1. 增加了新
- 不要为“非致命错误”自定义新异常类,除非调用方需要精确区分处理逻辑
- 避免把
ValueError和TypeError混用:int("1.5")抛ValueError(格式对但值非法),int(None)抛TypeError(类型根本不对) - 消息里别只写
"invalid input",要带上下文,比如f"expected positive int, got {x!r}"
用异常替代返回码(如 None 或 -1)是否更 Pythonic?
视情况。当“失败”是意外、罕见、需中断当前流程时,异常更合适;当“失败”是常规业务路径(比如查数据库没找到用户),返回 None 或空列表反而更轻量、更易组合。
容易踩的坑:把“找不到”当成异常,结果每次调用都得包一层 try,代码嵌套变深,阅读成本上升。
-
dict.pop(key, default)返回默认值比pop()抛KeyError更适合“可选移除”场景 - 用
next(iterator, default)替代手动try/except StopIteration - 异步代码中尤其注意:
await可能抛异常,但返回None是静默的,调试时容易漏掉“本该有值却没到”的问题
自定义异常要不要继承 Exception 还是 RuntimeError?
绝大多数情况直接继承 Exception。Python 官方文档明确建议:所有用户自定义异常应继承 Exception,而非其子类(如 RuntimeError),除非你刻意想表达某类运行时故障的语义。
性能影响几乎为零,但兼容性很重要:很多框架(如 Flask、Django)只捕获 Exception 及其子类,若你继承 BaseException(比如误用 SystemExit 的父类),可能被全局异常处理器忽略。
- 命名以
Error结尾,如ConfigLoadError,别用Exception - 不需要重写
__init__就能支持str(e)和repr(e),除非你要加额外字段 - 如果异常需要携带数据(如错误码、原始响应),用实例属性存,别塞进
args里靠位置索引取
if 还是 try。









