Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Decimal (十进制小数)

以下是一份 非常清晰、非常实用的 Python decimal 速查与最佳实践指南,尤其适用于你做 金融、金额、精度敏感计算 的场景。

🔥 1. decimal 是什么?

decimal.Decimal 是 Python 用来进行高精度、小数不会丢失的计算的数据类型。

适用场景:

  • 金融金额计算(避免浮点误差)
  • 需要精确的小数(如价格、费率、税率)
  • 对比 float,Decimal 完全不会出现 0.1 + 0.2 != 0.3 的问题

🧪 2. 与 float 的对比(直观示例)

>>> 0.1 + 0.2
0.30000000000000004     # 浮点误差

>>> from decimal import Decimal
>>> Decimal('0.1') + Decimal('0.2')
Decimal('0.3')           # 精确

🚀 3. 基本用法

3.1 创建 Decimal

必须用字符串初始化,否则仍然会带入浮点误差!

from decimal import Decimal

Decimal("1.23")   # 正确
Decimal(1.23)     # 错误,会带入浮点误差

3.2 基本计算

a = Decimal("1.2")
b = Decimal("1.3")

c = a + b      # 加
d = a * b      # 乘
e = b - a      # 减
f = b / a      # 除

🧭 4. 设置精度(上下文 Context)

全局设置:

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'))

🎚 5. 四舍五入量化(quantize)

这是金额最常用的操作。

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(银行家舍入)

🧩 6. 与 Float、int、str 的转换

Decimal("1.23")   # str -> Decimal

float(Decimal("1.23"))  # Decimal -> float

int(Decimal("3.14"))    # Decimal -> int

🧨 7. 避免混合类型计算

❗ 千万不要:

Decimal("1.2") + 1.2  # ❌
Decimal("1.2") * 3    # 可以,但建议保持一致

建议统一规范:

  • 金额统一用 Decimal
  • 永远使用字符串初始化

🏦 8. 金额计算最佳实践函数(你可直接加入 utils)

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')

🤖 9. 在你的实际项目(FastAPI + PostgreSQL)中的使用建议

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)

📌 10. 小结(速查版)

功能 写法
创建 Decimal Decimal(“1.23”)
设置精度 getcontext().prec = 10
四舍五入 .quantize(Decimal(“0.01”), ROUND_HALF_UP)
避免误差 不要用 Decimal(1.23)
JSON 转换 json.dumps(…, default=str)
金额最佳实践 用字符串创建,统一量化

Next

高精度计算

# 数字/浮点数 -> 转字符串 -> Decimal 计算 -> 将结果转为浮点数
float(Decimal(str(0.1)) + Decimal(str(0.2)))
# 0.3