跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

Python 返回值设计的最佳实践

应根据失败是否可预期来选择:可预期且可恢复时返回None或哨兵值,否则抛异常;多值返回优先用命名元组或数据类;提前返回宜限于函数开头的守门检查;显式标注->None有助于防止误用。 返回
None
还是抛异常?看调用方是否能合理处理失败 Python 不强制函数必须有明确返回值,但随意返回
None
容易埋雷。比如
dict.get()
返回
None
是安全的——调用方本就预期“可能没找到”;但
json.loads()
遇到非法 JSON 直接抛
JSONDecodeError
,因为解析失败不是“正常分支”,而是输入错误。 如果失败是业务逻辑中可预期、可恢复的情况(如查缓存未命中),返回
None
或特殊哨兵值(如
sentinel = object()
)更合适 如果失败意味着输入违法、状态异常或外部依赖不可用(如文件不存在、网络超时),该抛异常,别默默返回
None
别在同一个函数里混用:一会儿返回
dict
,一会儿返回
None
,又不加类型提示,调用方只能靠 try/except 猜
def find_user_by_id(user_id: int) -> Optional[User]: # 明确标注可能为 None,调用方有心理准备 return db.query(User).filter(User.id == user_id).first()
多值返回要不要用 tuple?优先考虑命名元组或数据类 Python 支持
return a, b, c
,解包也方便,但问题在于语义模糊:
x, y = process()
中的
x
和
y
到底代表什么?几个月后连你自己都得翻源码。 简单脚本、临时计算、且返回值含义极其明确(如
divmod()
)可用 tuple 一旦涉及两个以上值,或值有业务含义(如
status_code, headers, body
),立刻改用
namedtuple
、
dataclass
或
TypedDict
typing.NamedTuple
比普通
namedtuple
更好,支持类型注解,IDE 能补全,mypy 能校验
from typing import NamedTuple class HttpResponse(NamedTuple): status_code: int headers: dict body: bytes

def fetch(url: str) -> HttpResponse: ...

return
提前退出太多?说明函数职责过重 满屏
if ... return
看起来“简洁”,实则掩盖了逻辑分层问题。比如一个函数开头检查参数类型、非空、权限、配额、限流……每项失败都提前
return
,后续主逻辑缩进深、难测试、难复用。 提前返回只适合 守门人式检查 (如
if not user: return
),且应集中放在函数开头 权限、配额、限流等属于横切关注点,该抽成装饰器或中间件,别塞进业务函数里 如果不得不做多重校验,用 guard clause 模式:每个检查独立成行,失败统一抛特定异常(如
ValidationError
),让上层决定怎么响应
def create_order(items: list, user: User) -> Order: if not items: raise ValueError("items cannot be empty") if not user.is_active: raise PermissionError("user is disabled") # 主逻辑从这里开始,缩进浅、意图清 return Order.create(items, user)
类型提示写不写
-> None
?写了比不写强,但别为了类型而类型
def cleanup() -> None:
看似多余,其实有用:它告诉调用方“别指望这个函数给你回东西”,也堵死了误用
result = cleanup()
的可能。但问题在于,很多人把
-> None
当成形式主义,反而漏掉真正该标注的返回类型。 Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 立即学习 “ Python免费学习笔记(深入) ”; 所有无显式
return
的函数,Python 默认返回
None
,此时显式写
-> None
是好习惯 但如果你写了
-> None
,却在某个分支里
return "done"
,mypy 会报错——这反而是好事,逼你修正逻辑 别为了加类型提示硬拆函数:比如把
-> List[User]
改成
-> Optional[List[User]]
只为覆盖空列表场景,不如让空列表本身成为合法返回值 最常被忽略的一点:返回值设计不是孤立问题,它和错误传播路径、调用方的防御性编程习惯、以及团队对“空值容忍度”的共识强相关。写完一个函数,不妨问自己一句:如果我三天后第一次调用它,看到这个返回类型,会不会犹豫要不要加
if result is not None:
?

相关文章