page contents

Python 中千万不要直接返回 None!

有一次,我在做一个接口的时候,返回结果老是奇奇怪怪的。前端的同事说,有时候拿到的数据是个对象,有时候是 None,然后页面就直接白屏了。那天晚上我在工位上调试到快十一点,才发现是我在一个函数里写了个简单的 return None。

attachments-2025-10-h8jHRBHz68f2ec55d3938.png有一次,我在做一个接口的时候,返回结果老是奇奇怪怪的。前端的同事说,有时候拿到的数据是个对象,有时候是 None,然后页面就直接白屏了。那天晚上我在工位上调试到快十一点,才发现是我在一个函数里写了个简单的 return None。

说实话,这事看起来不起眼,但坑真不小。

None 并不是一个“安全”的返回值

Python 里 None 本质上是个“空值”,但问题在于,谁也不能保证下游的代码一定能正确处理这个空值。

比如这段代码:

def get_user(user_id):

    if user_id not in user_db:

        return None

    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,但其实更好的做法是——返回一个类型正确但内容为空的对象。

比如:

def get_user(user_id):

    return user_db.get(user_id, {})

这样即使查不到用户,返回的也是一个空字典 {}。 上游继续访问 user["name"] 也不会直接崩,而是拿到一个默认值。

当然,如果你担心空字典也会被误操作,可以用一个带默认行为的封装类:

class EmptyUser(dict):

    def __getitem__(self, key):

        return ""

def get_user(user_id):

    return user_db.get(user_id, EmptyUser())

这样既保证类型一致,又不至于出错。

对象方法中的 None 更危险

有一次我们系统的一个支付逻辑出错,就是因为 None。

def get_payment_info(order_id):

    if not order_id:

        return None

    return Payment.query(order_id)

然后调用方直接:

payment = get_payment_info(order_id)

payment.process()  # ❌ AttributeError: 'NoneType' object has no attribute 'process'

生产环境直接报错,支付线程挂了。后来我们统一改成:

class NullPayment:

    def process(self):

        print("跳过无效订单")

def get_payment_info(order_id):

    if not order_id:

        return NullPayment()

    return Payment.query(order_id)

这其实就是 “空对象模式” 的思想。 让返回值的行为一致,不让调用者分心去判断是不是 None。

函数返回 None 的“副作用”

更隐蔽的情况是,None 会让逻辑短路。

def get_user_name(user):

    return user.get("name")

name = get_user_name(None)

这里直接报错,因为 None 没有 .get() 方法。

如果是链式调用,就更容易埋雷:

def get_city_name(order):

    return order.user.address.city  # 如果 order.user 是 None 就崩

其实更好的写法是:

def get_city_name(order):

    if not getattr(order, "user", None):

        return ""

    if not getattr(order.user, "address", None):

        return ""

    return order.user.address.city

或者使用更优雅的空对象思想:

class NullAddress:

    city = ""

class NullUser:

    address = NullAddress()

class NullOrder:

    user = NullUser()

然后:

def get_city_name(order=None):

    order = order or NullOrder()

    return order.user.address.city

无论传不传,函数都能稳稳地跑完。

None 在集合中的陷阱

这个也很常见。 比如你写了个方法,用于从多个结果里取最大值:

def get_max_score(scores):

    return max(scores)

但有一天你传了个 [None, 90, 85] 进去,直接报:

TypeError: '>' not supported between instances of 'int' and 'NoneType'

正确的写法是:

def get_max_score(scores):

    return max((s for s in scores if s is not None), default=0)

别小看这个 default=0,它能救你一命。

实战建议:明确返回类型

这才是最核心的一点——函数的返回类型一定要稳定、可预期。

如果函数大概率返回字典,就不要偶尔返回 None。 如果返回列表,就算是空,也返回 []。 如果返回字符串,就返回 "" 而不是 None。

这点可以用类型注解强约束:

from typing import Dict

def get_user_info(user_id: int) -> Dict[str, str]:

    return user_db.get(user_id, {})

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

from typing import Optional

def get_user(user_id: int) -> Optional[dict]:

    ...

然后:

user = get_user(123)

if user is None:

    return "用户不存在"

这样才不会埋雷。

小结

返回 None 看似无害,其实是“类型不稳定”的罪魁祸首。 它会让调用者陷入一连串的判断、异常和不可预期的错误。

所以,别图省事去返回 None,返回一个合适的“空值”对象才是更优雅的做法。

最后送一句话:

“如果函数能不返回 None,那你就永远不用担心它什么时候爆炸。”

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2025-10-18 09:24
  • 阅读 ( 25 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1479 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2228 文章
  3. Pack 1479 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章