花拾录
← 返回知识库

Python 脚本最常见的五类低级报错:类型、格式化、日期、引号与除零

编程语言导入2026/09/220 阅读0 评论

一个人同时维护十几个数据分析、抓取、自动化脚本的时候,真正让人头大的往往不是那些复杂的算法问题,而是一批看起来"很低级"的小错误——它们出现的频率高得惊人,而且类型高度固定。

现象

一批脚本要么反复抛异常,要么算出来一组"不可能的数值":占比超过 100%、平均值是天文数字、某天的统计直接为空。报错信息五花八门,但翻来覆去就那么几类。典型的有下面五种:

第一类,类型不匹配。把整个列表传给 %d:

items = [1, 2, 3]
print("共 %d 条" % items)
# TypeError: %d format: a real number is required, not list

这里本意是打印条目数量,正确的写法应该是 % len(items)。

第二类,百分号被当成占位符。字符串里写了字面的 %,例如:

print("今日涨幅 +3%" % rate)
# TypeError: not all arguments converted during string formatting

Python 把 +3% 里的 % 当成了格式化占位符,而后面又跟了参数,于是语法上对不上。

第三类,把日期串直接转整数:

day = int("2026-09-07")
# ValueError: invalid literal for int() with base 10: '2026-09-07'

第四类,字符串里嵌套了同一种引号,直接语法错误:

sql = 'SELECT * FROM t WHERE name = 'abc''
# SyntaxError: invalid syntax

第五类,某天恰好没有样本,除法除零:

avg = total / count
# ZeroDivisionError: division by zero

根因

这五类看着零散,其实都指向同一个根源:在"快速写脚本"的心态下,把人类语言的直觉直接翻译成了代码,而 Python 对类型、对占位符、对字符边界的规则是严格的。

  • 格式化占位符(%d / %s)对参数类型有硬性要求,%d 只接受一个数值,不能喂整个容器。
  • Python 的 % 运算符承担了两种含义:字符串格式化运算符,和数值取模。写在字符串里又不转义时,解释器优先按"格式化"理解。
  • int() 只认纯数字字符串,不会替你剥掉连字符。日期是"带分隔符的字符串",不是"整数"。
  • 引号在词法分析阶段就划定了字符串边界。内外都用单引号时,解释器看到第一个内层单引号就认为字符串结束了。
  • 除法的分母来自"当天的样本数",而样本数在某些日期可能为零——这是数据层面的边界,不是代码逻辑能想当然的。

解决

逐个对照修:

格式化一律改用 f-string,它的语义清楚得多,也不用担心 % 被误读:

print(f"共 {len(items)} 条")
print(f"今日涨幅 +3%")

如果因为某些原因必须用 % 格式化,就把字面百分号写成 %% 转义。

日期先规范化再转数值:如果确实需要把 2026-09-07 变成一个可比较的整数(比如 20260907),先去掉分隔符:

day = int("2026-09-07".replace("-", ""))  # 20260907

嵌套引号换成不同的引号类型,外层双引号、内层单引号,或者用参数化查询彻底避免手工拼 SQL:

sql = "SELECT * FROM t WHERE name = 'abc'"

关键路径加防御性判断,分母为零时返回空值或默认值,而不是让它崩:

avg = total / count if count else 0

延伸与预防

这类错误的高频点其实非常固定:类型、格式化、日期、引号、除零。值得在写代码的时候就形成条件反射——

  • 看到 % 格式化时,先想一下字符串里有没有字面的百分号;
  • 看到 int() / float() 时,先确认输入是不是纯数字串;
  • 看到字符串里要嵌引号时,主动换一种引号;
  • 看到除法时,先问一句"分母会不会是 0"。

更进一步,把"一个人维护一堆脚本"这种场景配上最低限度的自动化:对核心函数写几个 assert 或小测试、脚本入口处加 python -W error 让警告暴露出来、用 ruff / flake8 这类工具做静态检查——它们能挡住相当一部分低级错误,比事后一个个翻日志要省事得多。

评论(0)

  • 还没有评论,来抢沙发~

相关文章