Python模块DLLs

30 投票
6 回答
42798 浏览
提问于 2025-04-11 09:30

有没有办法让一个Python模块加载我应用程序目录里的dll,而不是使用Python安装时自带的版本?我不想改动Python的安装,这样就需要制作安装程序,还得小心不要因为覆盖Python模块和改变dll版本而影响到其他人的应用程序……

具体来说,我希望Python使用我自己的sqlite3.dll版本,而不是Python自带的那个(因为自带的版本比较旧,似乎没有fts3模块)。

6 个回答

18

这个回答提到修改 os.environ['PATH'] 是对的,但我在使用 Python 3.9 的时候没能成功。结果我遇到了一个错误:

导入错误:在导入模块 X 时加载 DLL 失败:找不到指定的模块。

后来我发现,从 Python 3.8 开始,他们增加了一种更安全的机制来处理这个问题。你可以查看 os.add_dll_directory 的文档,链接在这里:https://docs.python.org/3/library/os.html#os.add_dll_directory

具体可以看看 Python 3.8 的新特性

在 Windows 上,扩展模块和通过 ctypes 加载的 DLL 的依赖关系现在被更安全地解决。只有系统路径、包含 DLL 或 PYD 文件的目录,以及通过 add_dll_directory() 添加的目录会被搜索以找到加载时的依赖关系。具体来说,PATH 和当前工作目录不再被使用,对这些的修改也不会对正常的 DLL 解析产生任何影响。如果你的应用依赖于这些机制,你应该检查 add_dll_directory() 是否存在,如果存在,就在加载库时使用它来添加你的 DLL 目录。

所以现在在 Python 3.8 及以后版本,这是新的解决方法:

import os
os.add_dll_directory('my-app-dir')

不过,旧的方法在 Python 3.7 及更早版本 仍然是正确的,你需要继续使用它:

import os
os.environ['PATH'] = 'my-app-dir' + os.pathsep + os.environ['PATH']

之后,我的模块和 DLL 依赖关系就成功加载了。

33

如果你在说的是Python模块的DLL文件,那么只需要简单地修改一下sys.path就可以了。不过,如果你说的是那些与DLL文件有关系的DLL,比如一个libfoo.dll是一个foo.pyd所依赖的,那么你就需要修改你的PATH环境变量。我之前写过一篇关于如何为PyGTK做这件事的文章,但在你的情况下,我觉得应该简单得多:

import os
os.environ['PATH'] = 'my-app-dir' + os.pathsep + os.environ['PATH']

这样做会把my-app-dir放到你Windows路径的最前面,我认为这也会影响DLL的加载顺序。

记住,你需要在加载相关的DLL之前做这件事,也就是说,在导入任何有用的东西之前。

不过,sqlite3可能有点特殊,因为它是和Python一起分发的;测试这个可能有点麻烦,所以我没有专门检查sqlite3.dll

7

好的,结果发现Python总是会在与pyd文件相同的文件夹里加载dll文件,不管你的Python和操作系统的路径设置是什么。

所以我需要把_python/v2.5/DLLS_文件夹里的_sqlite3.pyd_复制到我的应用程序目录里,那里有新的_sqlite3.dll_文件。这样就能加载我新的dll,而不是Python自带的那个(因为pyd文件似乎是根据PYTHONPATH来寻找的,尽管实际的dll文件并不是这样)。

撰写回答