You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用openpyxl保存Excel后公式无法计算,如何读取公式结果?

解决openpyxl写入Excel后无法读取公式计算结果的问题

我需要用Python往带公式的Excel文件写入数据,选用openpyxl库,但保存文件后公式无法自动计算——开启Data Only模式读取显示NaN,关闭则直接显示公式字符串。测试对比xlwings可以得到正确计算结果,但运行速度慢很多。

测试代码

import pandas as pd
import datetime
import xlwings as xw
from openpyxl import load_workbook

path = "你的文件路径.xlsx"

# 读取初始值
dec1 = pd.read_excel(path).iloc[26, 10]

# 使用xlwings写入并读取结果
str_dat2 = datetime.now()
exe_app = xw.App(visible=False)
xlwb = xw.Book(path)
xlwb.sheets['HURT'].range("C17").value = 'BASE_Q-1-23'
xlwb.sheets['HURT'].range("E17").value = 0.25
xlwb.sheets['HURT'].range("F17").value = 1500
xlwb.save(path)
xlwb.close()
exe_app.quit()
stp_dat3 = datetime.now()-str_dat2
dec3 = pd.read_excel(path).iloc[26, 10]

# 使用openpyxl写入并读取结果
str_dat1 = datetime.now()
wb = load_workbook(filename=path, read_only=False, keep_vba=True)
ws = wb['HURT']
ws['C17'] = 'BASE_Q-1-23'
ws['E17'] = 0.25
ws['F17'] = 1500
wb.save(path)
stp_dat2 = datetime.now()-str_dat1
dec2 = pd.read_excel(path).iloc[26, 10]

测试结果

Before changing file (value): NIE
Before changing file (formula): =IF(J22=100%,IF(AND($F$15<>"",J27>0),"TAK","NIE"),"NIE")

After changing file (openpyxl): nan it lasted: 0:00:00.166674
After changing file (xlwings): TAK it lasted: 0:00:02.496538

核心原因

openpyxl本身不具备公式计算能力,它仅负责读写Excel文件的内容(包括公式字符串),不会触发Excel的计算引擎更新公式结果。而xlwings是调用本地安装的Excel程序操作文件,因此能自动完成公式计算。

可行解决方法

方法1:openpyxl+win32com触发Excel计算(Windows环境)

保存文件后,调用Excel的COM接口打开文件,强制计算所有公式再保存,后续读取即可得到正确结果:

from openpyxl import load_workbook
import win32com.client as win32
import os

path = "你的文件路径.xlsx"

# 用openpyxl写入数据
wb = load_workbook(filename=path, read_only=False, keep_vba=True)
ws = wb['HURT']
ws['C17'] = 'BASE_Q-1-23'
ws['E17'] = 0.25
ws['F17'] = 1500
wb.save(path)
wb.close()

# 调用Excel COM接口计算公式
excel = win32.DispatchEx("Excel.Application")
excel.Visible = False
excel.DisplayAlerts = False
wb = excel.Workbooks.Open(os.path.abspath(path))
# 强制计算所有公式
wb.RefreshAll()
wb.CalculateUntilAsyncQueriesDone()
wb.Save()
wb.Close()
excel.Quit()

# 读取计算后的结果
dec2 = pd.read_excel(path).iloc[26, 10]

方法2:优化xlwings运行速度

xlwings的耗时主要来自Excel进程启动开销,可通过复用实例减少耗时:

import xlwings as xw
import pandas as pd
import datetime

path = "你的文件路径.xlsx"

# 复用Excel实例,避免重复启动
with xw.App(visible=False, add_book=False) as exe_app:
    str_dat2 = datetime.now()
    xlwb = exe_app.books.open(path)
    ws = xlwb.sheets['HURT']
    ws.range("C17").value = 'BASE_Q-1-23'
    ws.range("E17").value = 0.25
    ws.range("F17").value = 1500
    xlwb.save()
    xlwb.close()
    stp_dat3 = datetime.now()-str_dat2

dec3 = pd.read_excel(path).iloc[26, 10]

add_book=False避免创建默认空白工作簿,上下文管理器确保进程正确关闭,能有效降低启动耗时。

方法3:手动实现公式计算逻辑

如果公式逻辑简单,可直接在Python中复刻计算规则,完全脱离Excel引擎:

import pandas as pd

path = "你的文件路径.xlsx"
df = pd.read_excel(path)

# 写入数据(注意Excel行号对应DataFrame索引需减1)
df.at[16, 'C'] = 'BASE_Q-1-23'  # C17对应第16行
df.at[16, 'E'] = 0.25
df.at[16, 'F'] = 1500

# 复刻公式逻辑:=IF(J22=100%,IF(AND($F$15<>"",J27>0),"TAK","NIE"),"NIE")
j22 = df.iloc[21, 9]  # J22对应第21行第9列
f15 = df.iloc[14, 5]  # F15对应第14行第5列
j27 = df.iloc[26, 9]  # J27对应第26行第9列

if j22 == 1.0:  # 100%对应数值1.0
    if pd.notna(f15) and j27 > 0:
        result = "TAK"
    else:
        result = "NIE"
else:
    result = "NIE"

print(result)  # 直接输出计算结果

内容的提问来源于stack exchange,提问作者Mateusz Szymczak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 05:15:38