openpyxl默认保留公式需设data_only=False并用cell.value读取公式字符串;公式单元格data_type为'f'或value以'='开头;更新时仅写入数据区,保存后需在Excel中按F9重算。

openpyxl 读取 Excel 时公式默认被转成值,怎么保留?
默认用 load_workbook() 打开文件时,data_only=False(这是默认值),但很多人没意识到:**只有在打开时设置 keep_vba=False 且不触发计算,公式才真正“待命”**。更关键的是,你必须用 worksheet[cell].value 读取单元格——此时如果该单元格含公式,.value 返回的是公式字符串(如 '=SUM(A1:A10)'),而不是计算结果。
常见错误是误用 data_only=True(它强制把所有公式替换成当前计算值,不可逆),或用 .cell().value 后又手动覆盖公式内容。
- 确认打开方式:
wb = load_workbook('file.xlsx', data_only=False, keep_vba=False) - 检查公式是否还在:
ws['B2'].value若返回类似'=A1*1.1'的字符串,说明公式 intact - 不要对含公式的单元格调用
.value = ...赋值,除非你明确想删掉公式
只更新数据单元格,不碰公式所在单元格
实际场景中,公式通常在汇总行/列,原始数据在其他区域(比如 A 列是录入值,B 列是 =A1*1.2)。你要更新的只是 A 列数值,B 列让 Excel 自己重算——这就要求你精准识别哪些单元格该写入、哪些该跳过。
openpyxl 不提供“判断某单元格是否含公式”的快捷属性,但可通过 .data_type 和 .value 类型组合推断:
立即学习“Python免费学习笔记(深入)”;
-
cell.data_type == 'f'→ 明确是公式单元格(f表示 formula) -
isinstance(cell.value, str) and cell.value.startswith('=')→ 大概率是公式(但注意:也可能是文本型等号,需结合上下文) - 最稳妥做法:维护一个“数据区范围”,比如
data_range = 'A2:A100',只对这个范围内的单元格赋值
示例:只更新 A 列第 2–50 行的数据,B 列公式自动响应
for row in range(2, 51):
ws[f'A{row}'].value = new_data[row-2]
保存后公式不生效?检查 calculation_mode 和 Excel 实际行为
openpyxl 本身不执行公式计算,它只负责写入公式字符串和保存结构。你用 openpyxl 保存后双击打开 Excel,看到的仍是旧计算结果——因为 Excel 默认不自动重算(尤其当源文件是手动计算模式时)。
- Excel 文件的计算模式由
wb.calculation_properties控制,但 openpyxl 对它的支持有限;不能靠它触发实时计算 - 真正起作用的是:你在 Excel 中按
F9(重算全部)或Shift+F9(重算当前表) - 如果你用脚本后续调用 Excel COM 或 pywin32 自动化,可主动调用
Calculate()方法 - 导出给用户前,在 Excel 中另存为
.xlsx(非模板)并确保“公式→计算选项→自动”已勾选
批量更新大量数据时性能与内存注意事项
直接循环写入单个单元格(如 ws['A1'].value = x)在万行级别会明显变慢。这不是 Python 瓶颈,而是 openpyxl 每次赋值都触发内部状态更新。
- 优先用
ws.append()追加整行,或ws['A1:C100'] = [[...], [...], ...]批量写入二维列表 - 避免在循环里反复访问
ws.cell(),提前缓存行/列索引 - 如果原文件带大量样式、图表、条件格式,
load_workbook(..., read_only=False, keep_vba=False, data_only=False)是安全起点,但会吃更多内存 - 更新完别忘了
wb.save()—— 不调用它,所有变更全丢
公式本身不占额外内存,但 openpyxl 必须为每个 f 型单元格维护 formula 属性和依赖关系,所以含几千个公式的文件加载会比纯数据文件慢 2–3 倍。


















