Python技术迷

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 Dict

defget_user_info(user_id: int) -> Dict[str, str]:
return user_db.get(user_id, {})

或者用 Optional 明确说明可能是 None,但务必在调用方显式判断:

from typing import Optional

defget_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 全部免费领