Python多线程调用win32com可能遇到的问题解答

这是一件“悲哀”的事情,说出来给大家乐乐。

由于项目需要,需要用Python对word文档进行读写。我没多想,屁颠屁颠到pypi找了word操作库——python-docx。

刚开始用觉得还挺好用。后来随着项目深入,需要处理的word文件越来越大。

这个python-docx库的肩膀太小,负担不起。

因为它处理的东西都是放在内存里面,而且每次读写好像要跑个马拉松。文件越大,效率越慢。

没办法,我只能采用win32com组件调用word的com组件的方案。这个方案需要系统环境是windows,而且需要安装Office。所以开始就没考虑这个。(win32com组件可以在https://sourceforge.net/projects/pywin32/files/pywin32下载,我选的是220版本。根据系统和Python版本下载了64位的python2.7那个)

本篇博文,主要不是说如何用win32com读写word文档。

用win32com对word操作和写vba代码差不多,语法基本一致。简单贴上win32com调用word示例代码:

上面的test方法是给定word文档的路径,获取该文档里面表格的数量。

我在cmd命令行测试,发现word.Quit()执行之后,word的进程还存在!

我还可以重新再将这个应用显示出来。为了保险起见,加了一句删除变量的代码,才真正退出word进程。

不过一般在程序中执行没有这个问题。因为该方法执行完成之后,会自动清理内存,删除没有使用的变量等。

单单这段代码测试一点问题都没有。但放入到总程序里面就出现问题了!返回错误信息说没有CoInitialize初始化。

我写的总程序是一个总控制脚本,里面用到多线程。我就怀疑是不是多线程导致的问题。

搜索一下,发现确实和多线程有关系。

在多线程里面使用win32com调用com组件的时候,需要用pythoncom.CoInitialize初始化一下。

最后还需要用pythoncom.CoUninitialize释放资源。

上面代码改成这样:

修改之后,无论单独执行还是放到多线程里面执行都没问题了。

那这个CoInitialize是何方神圣?加了这个东西之后,在多线程就可以正常运行。

Coinitialize是Windows提供的API函数(好吧,还是微软惹的“祸”),用来告诉Windows系统单独一个线程创建COM对象。也就是说我这个多线程的脚本里面的线程和这个COM对象的线程创建一个套间,令其可以正常关联和执行。

看不懂?好吧,我也不是很清楚原理。反正,多线程使用win32com,就得加上这个。不喜欢Windows系统,问题多多。

另外,还有一个坑。

若我先手动打开一个Word文件,这时就运行了一个word进程。若执行Dispatch创建进程。

再设置word不可见。

但,我手动打开的Word进程的界面被隐藏了。

这说明一个问题,Dispatch若发现该进程已经存在的话,就不会创建新的进程。

若不创建新的进程,有些操作会有冲突,可能会影响到已经打开的Word文件。

这时,不能再使用Dispatch,用如下代码:

即可真正创建新进程,无论是否已经打开了一样的进程。

转载请注明出处:看飞碟 » Python多线程调用win32com可能遇到的问题解答

赞 (0) 送糖

评论 0

评论前必须登录!

登陆 注册

可爱的来客!请作者吃颗糖吧

支付宝扫一扫打赏

微信扫一扫打赏

你好,我是Jeson