page contents

看不懂 Python 报错?80% 的报错三行就够

Traceback 可能有二三十行,中间夹着 FastAPI、Django、requests 或者 pandas 的内部调用。那些栈不是完全没用,但第一遍通常不用细看。

attachments-2026-07-hW00p8uU6a6aabb46780b.png

Traceback (most recent call last):
  File "/srv/jobs/import_order.py", line 61, in load_row
    amount = int(row["pay_amount"])
ValueError: invalid literal for int() with base 10: ''

这段报错不长,但不少人看到 Traceback 就开始从第一行往下啃,文件路径、调用链、第三方包,全看一遍。

没必要。

这种错误我一般只看三处:

ValueError
import_order.py,第 61 行
int(row["pay_amount"])

已经够定位了。

ValueError 表示类型大致没错,但值不符合要求。代码想把一个字符串转成整数,实际拿到的却是空字符串。

问题不在 int(),更不在 Python 解释器。是上游数据脏了。

我见过有人遇到这个错误,第一反应是加 try...except:

def parse_amount(row):
    try:
        return int(row["pay_amount"])
    except Exception:
        return 0

代码是不报错了,账也可能对不上了。

金额字段为空,到底应该算 0、丢弃这一行,还是终止导入?这是业务规则,不该由一个宽泛的 except Exception 随手决定。

我会先把现场留下来:

def read_pay_amount(row: dict, line_no: int) -> int:
    raw = row.get("pay_amount")

    if raw is None or str(raw).strip() == "":
        raise ValueError(
            f"第 {line_no} 行 pay_amount 为空,order_no={row.get('order_no')}"
        )

    try:
        return int(str(raw).strip())
    except ValueError as exc:
        raise ValueError(
            f"第 {line_no} 行金额格式错误,pay_amount={raw!r},"
            f"order_no={row.get('order_no')}"
        ) from exc

这样下次日志不会只剩一句冷冰冰的:

invalid literal for int()

而是能直接看到哪一行、哪个订单、原始值是什么。

这才叫能排查的异常。

看 Python 报错,我的顺序一直比较固定。

先看最后一行。

KeyError: 'user_id'

别急着搜 KeyError 是什么意思。代码在用:

payload["user_id"]

但字典里没有这个键。

先打印键,不要直接把整个请求体扔进日志,里面可能有手机号、令牌之类的东西。

logger.warning(
    "callback 缺少 user_id,keys=%s,request_id=%s",
    sorted(payload.keys()),
    request_id,
)

再看离异常最近的业务代码。

Traceback 可能有二三十行,中间夹着 FastAPI、Django、requests 或者 pandas 的内部调用。那些栈不是完全没用,但第一遍通常不用细看。

从下往上找,找到第一个属于自己项目的文件:

File "/srv/api/payment.py", line 84, in build_callback

先查这一行。

第三方包报错,很多时候只是替你的错误数据背锅。

例如:

TypeError: Object of type datetime is not JSON serializable

最后落在:

body = json.dumps(result)

json.dumps() 没坏,是 result 里混进了 datetime。

我一般不会把所有对象都粗暴转成字符串,而是把允许出现的时间字段明确处理掉:

from datetime import datetime
import json


def encode_callback(data: dict) -> str:
    cleaned = {}

    for field, value in data.items():
        if isinstance(value, datetime):
            cleaned[field] = value.isoformat(timespec="seconds")
        else:
            cleaned[field] = value

    return json.dumps(cleaned, ensure_ascii=False)

剩下那一行,是出错代码附近的真实输入。

很多报错单看异常类型不够。比如:

AttributeError: 'NoneType' object has no attribute 'get'

你当然知道某个变量是 None,但它为什么是 None?

看代码:

profile = cache_client.get_json(cache_key)
city = profile.get("city")

这时我先查缓存查询结果,不会急着给第二行补个默认值。

profile = cache_client.get_json(cache_key)

if profile is None:
    logger.error(
        "用户资料缓存未命中,user_id=%s,cache_key=%s",
        user_id,
        cache_key,
    )
    raise LookupError(f"用户资料不存在,user_id={user_id}")

如果这里本来允许缓存未命中,那就回源数据库;如果不允许,就明确失败。最烦的是悄悄写成:

profile = cache_client.get_json(cache_key) or {}

随后程序继续跑,最后在更远的地方因为缺字段报错。原始现场反而被抹掉了。

还有一种报错,最后一行看着很吓人:

requests.exceptions.JSONDecodeError:
Expecting value: line 1 column 1 (char 0)

不少人会怀疑接口返回的 JSON 格式错了。

我第一眼先看响应状态码和响应头。对方可能返回的是 502 页面,甚至是一段空字符串。

resp = session.get(url, timeout=(2, 5))

logger.info(
    "remote response status=%s content_type=%s body_size=%s",
    resp.status_code,
    resp.headers.get("Content-Type"),
    len(resp.content),
)

resp.raise_for_status()

if "application/json" not in resp.headers.get("Content-Type", ""):
    raise RuntimeError(
        f"远端返回非 JSON,status={resp.status_code},"
        f"content_type={resp.headers.get('Content-Type')}"
    )

data = resp.json()

Python 的 Traceback 不是让你从头背到尾的。

先抓住最后一行的异常类型和信息,再找到最近的业务代码,最后核对那一行拿到的真实数据。多数普通报错,到这里已经露底了。

剩下那一小部分,才值得继续往线程、网络、依赖版本和解释器内部追。

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

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

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

 

  • 发表于 2026-07-30 09:41
  • 阅读 ( 38 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

2315 篇文章

作家榜 »

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