Python调用csv.DictWriter写入CSV时去除科学计数法避免精度丢失
Python写入CSV大浮点数自动转科学计数法、精度丢失解决方案
问题核心原因
- 原生Python
float是双精度类型,有效数字仅15-17位,示例代码中定义的几十位浮点数在赋值阶段就已经出现精度损失,不是CSV写入环节才导致的丢精度 - 直接将列表作为单元格值传入
csv.DictWriter.writerow()时,模块会自动对列表调用str()做类型转换,大浮点数转字符串默认使用科学计数法格式 - 常规字符串格式化操作如果基于已经丢精度的
float类型处理,无法还原原始数值,解决不了根本问题
可落地实现方案
方案核心逻辑:用Decimal类型存储大数值从根源避免精度丢失,自定义数值格式化逻辑禁用科学计数法,流式写入适配大规模数据场景。
import csv from decimal import Decimal csv_file = r"D:/temp/test.csv" # 注意:大数值禁止直接定义为float类型,通过字符串传入Decimal构造,从源头保证精度 # 若原始数据来自接口、数据库等数据源,直接取数值字符串传入Decimal即可,不要做float中转 long_num_dict = { 'number1': [ Decimal("123456789984987954654687654.20"), Decimal("19879842619984987954654687654.20") ], 'number2': [ Decimal("515456789984987954654687654.20"), Decimal("19879842619989875465654687654.20") ] } def format_decimal_num(num: Decimal) -> str: """将Decimal格式化为无科学计数法的定点数字符串""" return format(num, 'f') def process_cell_val(val): """处理单元格值,兼容单个数值、列表类型,自动格式化所有大数字""" if isinstance(val, list): processed_item_list = [] for item in val: if isinstance(item, Decimal): processed_item_list.append(format_decimal_num(item)) else: processed_item_list.append(str(item)) # 自定义拼接,避免默认str(list)给数值加单引号 return f"[{', '.join(processed_item_list)}]" elif isinstance(val, Decimal): return format_decimal_num(val) # 字符串、整数等常规类型直接返回原值 return val # 写入时指定newline=''避免CSV生成多余空行,指定utf-8编码兼容多环境打开 with open(csv_file, 'w', newline='', encoding='utf-8') as f: writer = csv.DictWriter(f, fieldnames=long_num_dict.keys()) writer.writeheader() # 逐值处理后写入,大场景下可替换为逐行读取、逐行处理、逐行写入的流式逻辑 processed_row = {col_name: process_cell_val(col_val) for col_name, col_val in long_num_dict.items()} writer.writerow(processed_row)
运行后生成的CSV内容如下,无科学计数法、无精度丢失:
number1,number2 "[123456789984987954654687654.20, 19879842619984987954654687654.20]","[515456789984987954654687654.20, 19879842619989875465654687654.20]"
大规模数据场景适配注意事项
- 禁止一次性加载全量数据到内存,若待处理数据量较大,采用逐行读取源数据、逐行做格式化处理、逐行调用
writer.writerow()的流式处理逻辑,内存占用不会随数据量上涨 Decimal格式化性能足够支撑百万级以上数值处理,无明显性能瓶颈,比pandas默认写入逻辑的精度稳定性更高- 若使用pandas处理,不要直接用默认
to_csv写入大数值列,需提前将所有大数值列转换为格式化后的字符串类型,否则pandas会默认将数值转为float64类型,同样会出现科学计数法和精度丢失问题 - 所有大数值处理环节禁止出现
float类型中转,否则会直接引入不可逆的精度损失
内容的提问来源于stack exchange,提问作者Flabala
相关产品推荐
相关产品推荐

