我们有一段代码使用 PyWin32,偶尔也会调用 Py_Finalize() 和 Py_Initialize() 来重新初始化 python。我们发现了一个错误,其中动态创建的类class error
是从 pywintypes 中的字符串创建的PyRun_String()
(PyWinTypesmodule.cpp,第 860 行),在重新初始化后不会重新创建。此类最终在重新初始化后被使用,并在尝试调用该函数时抛出“NoneType is not callable”错误len()
。
Py_Finalize()
我们已经观察到,如果在调用之前立即调用PyWinTypes export ,则错误停止发生PyWinGlobals_Free()
,它位于上面链接的同一源文件中。
在 PyWin32 代码库的其他地方(在dllmain.cpp中),有以下函数,在 regsvr32.exe 中进行 COM 注册/取消注册后清理时调用该函数:
void PyCom_DLLReleaseRef(void)
{
/*** NOTE: We no longer finalize Python EVER in the COM world
see pycom-dev mailing list archives from April 2000 for why
***/
// Must be thread-safe, although cant have the Python lock!
// only needed when we finalize.
// CEnterLeaveFramework _celf;
LONG cnt = InterlockedDecrement(&g_cLockCount);
// Not optimal, but anything better is hard - g_cLockCount
// could always transition 1->0->1 at some stage, screwing this
// up. Oh well...
if (cnt==0) {
// Send a quit message to the registered thread (if we have one)
if (dwQuitThreadId)
PostThreadMessage(dwQuitThreadId, WM_QUIT, 0, 0);
/*** Old finalize code
if (bDidInitPython) {
PyEval_RestoreThread(ptsGlobal);
PyWinGlobals_Free();
FreeGatewayModule();
Py_Finalize();
bDidInitPython=FALSE;
}
***/
}
}
这里有两点值得注意:
顶部有一个神秘的注释,暗示在这种情况下没有最终确定 Python 是有原因的。不幸的是,它所引用的“pycom-dev”邮件列表似乎不再存在。我认为这是有问题的线程的正确链接,但 pythonpros.com 似乎是一些 sedo 域停放的东西。
注释掉的“旧的最终确定代码”确实在确定 python 之前调用了 PyWinGlobals_Free(),这表明我们的修复可能在正确的轨道上。然而,除了源代码中这段神秘的代码片段之外,我们还没有在网络上找到任何文档或信息,表明在使用 PyWin32 时,在最终确定 python 之前必须做任何特别的事情。还有其他一些调用:FreeGatewayModules() 和 PyEval_RestoreThread()。我不确定我们是否应该自己调用这些。
我们的修复似乎有效,在没有更多信息的情况下,我们可能会接受它,但如果能得到一些确认会很好。