Python 中千万不要直接返回 None
有一次,我在做一个接口的时候,返回结果老是奇奇怪怪的。前端的同事说,有时候拿到的数据是个对象,有时候是 None,然后页面就直接白屏了。那天晚上我在工位上调试到快十一点,才发现是我在一个函数里写了个简单的 return None。
说实话,这事看起来不起眼,但坑真不小。
None 并不是一个“安全”的返回值
Python 里 None 本质上是个“空值”,但问题在于,谁也不能保证下游的代码一定能正确处理这个空值。
比如这段代码:
defget_user(user_id):
if user_id notin user_db:
returnNone
return user_db[user_id]user = get_user(123)
print(user["name"]) # ❌ TypeError: 'NoneType' object is not subscriptable
这就炸了。 为什么?因为开发者在用 get_user 的时候默认以为一定会返回字典,没想到是 None。
所以,一旦你返回 None,就等于在下游埋下了一颗炸弹。
返回空对象比返回 None 安全太多了
很多人图省事,觉得反正 “没有数据” 就 return None,但其实更好的做法是——返回一个类型正确但内容为空的对象。
比如:
defget_user(user_id):
return user_db.get(user_id, {})
这样即使查不到用户,返回的也是一个空字典 {}。 上游继续访问 user["name"] 也不会直接崩,而是拿到一个默认值。
当然,如果你担心空字典也会被误操作,可以用一个带默认行为的封装类:
classEmptyUser(dict):
def__getitem__(self, key):
return""defget_user(user_id):
return user_db.get(user_id, EmptyUser())
这样既保证类型一致,又不至于出错。
对象方法中的 None 更危险
有一次我们系统的一个支付逻辑出错,就是因为 None。
defget_payment_info(order_id):
ifnot order_id:
returnNone
return Payment.query(order_id)
然后调用方直接:
payment = get_payment_info(order_id)
payment.process() # ❌ AttributeError: 'NoneType' object has no attribute 'process'
生产环境直接报错,支付线程挂了。后来我们统一改成:
classNullPayment:
defprocess(self):
print("跳过无效订单")defget_payment_info(order_id):
ifnot order_id:
return NullPayment()
return Payment.query(order_id)
这其实就是 “空对象模式” 的思想。 让返回值的行为一致,不让调用者分心去判断是不是 None。
函数返回 None 的“副作用”
更隐蔽的情况是,None 会让逻辑短路。
defget_user_name(user):
return user.get("name")name = get_user_name(None)
这里直接报错,因为 None 没有 .get() 方法。
如果是链式调用,就更容易埋雷:
defget_city_name(order):
return order.user.address.city # 如果 order.user 是 None 就崩
其实更好的写法是:
defget_city_name(order):
ifnot getattr(order, "user", None):
return""
ifnot getattr(order.user, "address", None):
return""
return order.user.address.city
或者使用更优雅的空对象思想:
classNullAddress:
city = ""classNullUser:
address = NullAddress()
classNullOrder:
user = NullUser()
然后:
defget_city_name(order=None):
order = order or NullOrder()
return order.user.address.city
无论传不传,函数都能稳稳地跑完。
None 在集合中的陷阱
这个也很常见。 比如你写了个方法,用于从多个结果里取最大值:
defget_max_score(scores):
return max(scores)
但有一天你传了个 [None, 90, 85] 进去,直接报:
TypeError: '>' not supported between instances of 'int' and 'NoneType'
正确的写法是:
defget_max_score(scores):
return max((s for s in scores if s isnotNone), default=0)
别小看这个 default=0,它能救你一命。
实战建议:明确返回类型
这才是最核心的一点——函数的返回类型一定要稳定、可预期。
如果函数大概率返回字典,就不要偶尔返回 None。 如果返回列表,就算是空,也返回 []。 如果返回字符串,就返回 "" 而不是 None。
这点可以用类型注解强约束:
from typing import Dictdefget_user_info(user_id: int) -> Dict[str, str]:
return user_db.get(user_id, {})
或者用 Optional 明确说明可能是 None,但务必在调用方显式判断:
from typing import Optionaldefget_user(user_id: int) -> Optional[dict]:
...
然后:
user = get_user(123)
if user isNone:
return"用户不存在"
这样才不会埋雷。
小结
返回 None 看似无害,其实是“类型不稳定”的罪魁祸首。 它会让调用者陷入一连串的判断、异常和不可预期的错误。
所以,别图省事去返回 None,返回一个合适的“空值”对象才是更优雅的做法。
最后送一句话:
“如果函数能不返回 None,那你就永远不用担心它什么时候爆炸。”
——一个曾被 None 坑过无数次的程序员
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领