当 .py 和 .exe 中的 运行 时,Win32com excel find() 输出不一致
Win32com excel find() output is not consistent when run in .py and in .exe
当我 运行 下面的代码时,我在 .py 中 运行 与我在 .exe 中使用 pyinstaller运行 运行 时得到不同的结果
import win32com.client
import os
ConfigMacroName = "test.xls"
xl=win32com.client.Dispatch("Excel.Application")
Configmacrowb = xl.Workbooks.Open(os.getcwd()+ "\Completed\" + ConfigMacroName)
SlotPlansheet = Configmacrowb.Sheets("SlotPlan")
Header = SlotPlansheet.Rows(1)
SOcol = Header.Find('SO', LookAt=1).Column #I used LookAt=1 which is equivalent to LookAt:=xlWhole in excel VBA
SOlinecol = Header.Find('SO Line').Column
print("SO is " + str(SOcol) + "\nSo line is " + str(SOlinecol))
SlotPlansheet = None
Configmacrowb.Close(False)
Configmacrowb = None
xl.Quit()
xl = None
excel输入
.py中的输出
.exe 中的输出
.py 文件中的输出是我需要的正确输出。如果我 运行 它在 .exe 中,将会有重复的变量,因为它们都将引用 B 列。对于临时解决方案,我可以循环遍历 header 来检查每个单元格。
但是我经常使用 find() 函数所以我不知道我的其他程序是否也受到这种不一致的影响
尝试将对象创建行更改为:
xl=win32com.client.gencache.EnsureDispatch(‘Excel.Application’)
根据我的经验,win32com.client.Dispatch()
函数有时会导致问题,因为它不会保证 运行 每次运行时都得到相同的结果。调用者不知道他们是否有 early- 或 late-bound 对象。如果您没有缓存的 makepy 文件,那么您将获得一个 late-bound IDispatch 自动化接口,但是如果 win32com 找到一个 early-bound 接口,那么它将使用它(即使创建它的不是您的程序) .因此,之前 运行 正常的代码可能会停止工作。
除非你有充分的理由无动于衷,否则我认为最好是明确地选择 win32com.client.gencache.EnsureDispatch()
或 win32com.client.dynamic.Dispatch()
或 late-binding。我通常选择 EnsureDispatch() 路由,因为它更快,强制执行 case-sensitivity,并允许访问类型库中的任何常量(例如 win32com.client.constants.xlWhole
),而不是依赖 'magic' 整数。
此外,在过去,我在索引方面遇到过奇怪的行为(例如这个 SO question),并且通过删除任何 gencache 包装器(见下文)解决了这个问题。
将此行添加到您的调试代码中:
print('Cache directory:',win32com.client.gencache.GetGeneratePath())
这将告诉您 gencache
early-binding python 文件的生成位置,以及 win32com.client.Dispatch()
将在何处查找任何缓存的包装文件以尝试 early-binding.如果要清除生成文件的缓存,只需删除该目录的内容即可。看看OP的两条路由是否有相同的目录会很有趣。
当我 运行 下面的代码时,我在 .py 中 运行 与我在 .exe 中使用 pyinstaller运行 运行 时得到不同的结果
import win32com.client
import os
ConfigMacroName = "test.xls"
xl=win32com.client.Dispatch("Excel.Application")
Configmacrowb = xl.Workbooks.Open(os.getcwd()+ "\Completed\" + ConfigMacroName)
SlotPlansheet = Configmacrowb.Sheets("SlotPlan")
Header = SlotPlansheet.Rows(1)
SOcol = Header.Find('SO', LookAt=1).Column #I used LookAt=1 which is equivalent to LookAt:=xlWhole in excel VBA
SOlinecol = Header.Find('SO Line').Column
print("SO is " + str(SOcol) + "\nSo line is " + str(SOlinecol))
SlotPlansheet = None
Configmacrowb.Close(False)
Configmacrowb = None
xl.Quit()
xl = None
excel输入
.py中的输出
.exe 中的输出
.py 文件中的输出是我需要的正确输出。如果我 运行 它在 .exe 中,将会有重复的变量,因为它们都将引用 B 列。对于临时解决方案,我可以循环遍历 header 来检查每个单元格。
但是我经常使用 find() 函数所以我不知道我的其他程序是否也受到这种不一致的影响
尝试将对象创建行更改为:
xl=win32com.client.gencache.EnsureDispatch(‘Excel.Application’)
根据我的经验,win32com.client.Dispatch()
函数有时会导致问题,因为它不会保证 运行 每次运行时都得到相同的结果。调用者不知道他们是否有 early- 或 late-bound 对象。如果您没有缓存的 makepy 文件,那么您将获得一个 late-bound IDispatch 自动化接口,但是如果 win32com 找到一个 early-bound 接口,那么它将使用它(即使创建它的不是您的程序) .因此,之前 运行 正常的代码可能会停止工作。
除非你有充分的理由无动于衷,否则我认为最好是明确地选择 win32com.client.gencache.EnsureDispatch()
或 win32com.client.dynamic.Dispatch()
或 late-binding。我通常选择 EnsureDispatch() 路由,因为它更快,强制执行 case-sensitivity,并允许访问类型库中的任何常量(例如 win32com.client.constants.xlWhole
),而不是依赖 'magic' 整数。
此外,在过去,我在索引方面遇到过奇怪的行为(例如这个 SO question),并且通过删除任何 gencache 包装器(见下文)解决了这个问题。
将此行添加到您的调试代码中:
print('Cache directory:',win32com.client.gencache.GetGeneratePath())
这将告诉您 gencache
early-binding python 文件的生成位置,以及 win32com.client.Dispatch()
将在何处查找任何缓存的包装文件以尝试 early-binding.如果要清除生成文件的缓存,只需删除该目录的内容即可。看看OP的两条路由是否有相同的目录会很有趣。