用dtype或converters强制指定长数字列为str最有效,openpyxl可绕过类型推断读取原始值,导出时需用openpyxl设置文本格式“@”防止自动转换。

Python用pandas.read_excel或openpyxl读取Excel时,长数字(如18位身份证号、订单号)被自动转成科学计数法或浮点近似值,本质是Excel本身把单元格格式设为“常规”或“数值”,而Python库默认按数值解析——这不是Python的bug,是数据类型推断逻辑和Excel存储机制共同导致的。
用dtype参数强制指定列类型为字符串
最直接有效的办法是在读取时就阻止数值解析。对已知含长数字的列,显式指定dtype为str:
df = pd.read_excel("data.xlsx", dtype={"order_id": str, "id_card": str})
注意:dtype只对列名精确匹配生效;如果列名带空格或不可见字符,先用pd.read_excel("data.xlsx", nrows=0).columns.tolist()确认真实列名。若整表都是文本型数字,可统一用dtype=str,但会丢失其他列的原始数值类型,慎用。
用converters在读取过程中做类型转换
比dtype更灵活,尤其适合列名不固定或需额外清洗的场景。它在解析每一行时立即应用函数,不会受后续类型推断干扰:
df = pd.read_excel("data.xlsx", converters={"order_id": str, "phone": lambda x: str(x).strip()})
常见陷阱:
-
converters函数接收的是Excel单元格原始值(可能是float、int或None),不是字符串,所以str(x)必须能处理nan——建议写成lambda x: "" if pd.isna(x) else str(int(x)) if isinstance(x, float) and x.is_integer() else str(x) - 如果Excel里该列混有纯数字和带字母的编号(如“A12345678901234567”),
str转换仍安全;但用int会报错
用openpyxl读取原始字符串值(绕过pandas类型推断)
当pandas的dtype或converters仍出错(比如Excel里数字被存为“数值格式+自定义显示”),就得退到底层:用openpyxl直接读单元格的.value或.hyperlink等属性。关键点是区分“显示值”和“存储值”:
from openpyxl import load_workbook<br>wb = load_workbook("data.xlsx", data_only=True)<br>ws = wb.active<br>cell_value = ws["A2"].value # 返回Excel中实际存储的值(可能是float)<br>cell_text = ws["A2"].value # 注意:openpyxl不直接提供“显示文本”,需配合number_format判断
更稳妥的做法是启用data_only=False(默认),然后检查cell.number_format是否包含"@"(文本格式)或"General"(常规),再决定是否强制str(cell.value)。但多数情况下,直接用data_only=True + str(cell.value)已覆盖90%场景。
真正麻烦的不是读取,而是后续导出——如果用df.to_excel写回去,即使源数据是字符串,Excel打开后仍可能自动转成数值。解决方法是在写入时用openpyxl引擎并设置列格式:workbook.add_format({"num_format": "@"}),否则Excel会再次“好心”帮你转。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











