使用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
相关产品推荐
相关产品推荐

