必须用 decimal 而非 float 的场景是金融计算、会计对账等要求十进制小数精确表示的场合,因 float 基于二进制存在 0.1+0.2≠0.3 等精度问题,而 decimal 可确保十进制运算准确。

什么时候必须用 decimal,而不是 float
金融计算、会计对账、任何要求「十进制小数精确表示」的场景,decimal 不是“更好”,而是“唯一正确”。float 基于二进制 IEEE 754,0.1 + 0.2 ≠ 0.3 是常态;而 decimal 按十进制算,0.1 + 0.2 就是 0.3。
常见错误现象:float 累加金额出现 199.99999999999997 或 200.00000000000003;数据库存入后读出值与原始值不一致(尤其 PostgreSQL 的 NUMERIC 字段)。
- 银行转账、发票明细、税率计算、库存数量(带小数)必须用
Decimal - 科学计算、机器学习权重、物理模拟——用
float更合适,decimal会慢且无意义 -
decimal不解决舍入逻辑问题,它只保证“按指定精度做十进制运算”,舍入方式仍需显式指定
Decimal 初始化时字符串比数字更安全
用字符串初始化 Decimal,才能完全避开 float 的精度污染。写 Decimal(0.1) 看似方便,实则已把 float 的误差带进来了。
示例对比:
立即学习“Python免费学习笔记(深入)”;
系统包含模块:1、卖场系统适用客户:实体卖场,可以分类管理,每个分类设置一个客服,客服可以使用手机管理分类商品2、万能表单用户可以自定义表单字段,收集各样信息,并可以导出Excel3、第三方接口方便用户自己开发,目前仅支持text格式4、留言板可以显示用户的头像和昵称5、场景二维码这是高级接口的使用,方便统计用户来源6、一键分享一个仿微信公众号详情界面,可以分享到朋友圈7、婚纱摄影一个相册+店面展
from decimal import Decimal
print(Decimal(0.1)) # Decimal('0.1000000000000000055511151231257827021181583404541015625')
print(Decimal('0.1')) # Decimal('0.1')- 永远优先用字符串:
Decimal('19.99')、Decimal('1e-3') - 从用户输入、CSV、JSON 解析来的数字字符串,直接传给
Decimal,别先转float - 数据库 ORM(如 SQLAlchemy)返回的
decimal.Decimal对象可直接用;但若字段类型是Float,读出来已是float,再包一层Decimal也救不回精度
getcontext().prec 控制的是运算精度,不是显示位数
getcontext().prec = 2 并不会让 Decimal('1.234') 变成 '1.2';它影响的是后续所有算术运算的中间结果精度。这是最常被误解的一点。
比如:
from decimal import Decimal, getcontext
getcontext().prec = 2
a = Decimal('1.23') + Decimal('2.45') # 结果是 Decimal('3.7'),不是 '3.68'-
prec是“有效数字位数”,不是“小数点后几位”——Decimal('123.456').quantize(Decimal('0.01'))才控制小数位 - 不同业务模块可能需要不同精度(如汇率保留 6 位,商品价格保留 2 位),别全局设死
getcontext().prec - 多线程下
getcontext()是线程局部的,但修改它会影响当前线程所有后续运算,建议在关键计算前显式设置并恢复
和数据库交互时,注意 ORM 和驱动层的隐式转换
即使你代码里全程用 Decimal,如果数据库驱动或 ORM 把它自动转成 float 再塞进 SQL,精度就丢了。PostgreSQL 的 psycopg2 默认支持 Decimal,但 MySQL 的 pymysql 在某些版本里会把 DECIMAL 字段读作 float。
- 检查 ORM 配置:SQLAlchemy 中确保列定义为
Column(DECIMAL(precision=10, scale=2)),而非Float - 测试读写闭环:写入
Decimal('123.45'),再查出来打印type()和repr(),确认仍是Decimal且值未变 - 避免用
str()或float()中间转换:比如日志里打str(my_decimal)没问题,但float(my_decimal)一调就崩
真正麻烦的从来不是怎么创建一个 Decimal,而是整条链路——从输入解析、中间计算、ORM 映射、到最终展示——有没有哪一环偷偷把它变成了 float。这种隐式转换一旦发生,前面所有谨慎初始化都白搭。









