Decimal (十进制小数)
以下是一份 非常清晰、非常实用的 Python decimal 速查与最佳实践指南,尤其适用于你做 金融、金额、精度敏感计算 的场景。
decimal.Decimal 是 Python 用来进行高精度、小数不会丢失的计算的数据类型。
适用场景:
- 金融金额计算(避免浮点误差)
- 需要精确的小数(如价格、费率、税率)
- 对比 float,Decimal 完全不会出现 0.1 + 0.2 != 0.3 的问题
>>> 0.1 + 0.2
0.30000000000000004 # 浮点误差
>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.2')
Decimal('0.3') # 精确
❗ 必须用字符串初始化,否则仍然会带入浮点误差!
from decimal import Decimal
Decimal("1.23") # 正确
Decimal(1.23) # 错误,会带入浮点误差
a = Decimal("1.2")
b = Decimal("1.3")
c = a + b # 加
d = a * b # 乘
e = b - a # 减
f = b / a # 除
全局设置:
from decimal import Decimal, getcontext
getcontext().prec = 10 # 设置精度为 10 位
局部设置:
from decimal import localcontext
with localcontext() as ctx:
ctx.prec = 5
print(Decimal('1') / Decimal('7'))
这是金额最常用的操作。
from decimal import Decimal, ROUND_HALF_UP
# 保留 2 位小数
value = Decimal("3.14159").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
print(value) # 3.14
常见 rounding 方法:
- ROUND_HALF_UP(最常用,四舍五入)
- ROUND_DOWN(向下取)
- ROUND_UP(向上取)
- ROUND_HALF_EVEN(银行家舍入)
Decimal("1.23") # str -> Decimal
float(Decimal("1.23")) # Decimal -> float
int(Decimal("3.14")) # Decimal -> int
❗ 千万不要:
Decimal("1.2") + 1.2 # ❌
Decimal("1.2") * 3 # 可以,但建议保持一致
建议统一规范:
- 金额统一用 Decimal
- 永远使用字符串初始化
from decimal import Decimal, ROUND_HALF_UP
def money(value: str | float | Decimal) -> Decimal:
"""金额转换为 2 位小数 Decimal"""
if isinstance(value, float):
value = str(value)
return Decimal(value).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
示例:
money("1.236") # Decimal('1.24')
money(1.2) # Decimal('1.20')
money(Decimal("3")) # Decimal('3.00')
SQLAlchemy 字段:
from sqlalchemy import Numeric
price = Column(Numeric(10, 2)) # Decimal 会自动映射
Pydantic 转换:
Pydantic 会自动把 Numeric -> Decimal。
接口数据 JSON 序列化:
你需要 Decimal -> str,否则无法 JSON 化
import json
from decimal import Decimal
json.dumps({"price": Decimal("1.23")}, default=str)
| 功能 | 写法 |
|---|---|
| 创建 Decimal | Decimal(“1.23”) |
| 设置精度 | getcontext().prec = 10 |
| 四舍五入 | .quantize(Decimal(“0.01”), ROUND_HALF_UP) |
| 避免误差 | 不要用 Decimal(1.23) |
| JSON 转换 | json.dumps(…, default=str) |
| 金额最佳实践 | 用字符串创建,统一量化 |
高精度计算
# 数字/浮点数 -> 转字符串 -> Decimal 计算 -> 将结果转为浮点数
float(Decimal(str(0.1)) + Decimal(str(0.2)))
# 0.3