我遇到了同样的问题,发现了这个问题。但是从这里的答案我无法解决我的问题。我开始调试 cpython 代码,并认为我可能会发现一个错误。因此,我在 python 问题跟踪器上打开了一个问题。
我的错误是我不明白Py_SetPath 会清除所有推断的路径。
所以调用这个函数时需要设置所有路径。
为了完成,我还复制了下面对话中最重要的部分。
我的原始问题文本
我自己在 Windows 上使用 Visual Studio 2017 编译了 CPython 3.7.3 的源代码以及一些包,例如 numpy。当我启动 Python 解释器时,我可以导入和使用 numpy。但是,当我通过 C-API 运行相同的脚本时,我得到一个 ModuleNotFoundError。
所以我做的第一件事是检查 numpy 是否在我的站点包目录中,并且确实有一个名为 numpy-1.16.2-py3.7-win-amd64.egg 的文件夹。 (有道理,因为python解释器可以找到numpy)
接下来我做的是获取有关通过 C-API 运行脚本时创建的 sys.path 变量的一些信息。
#### sys.path content ####
C:\Work\build\product\python37.zip
C:\Work\build\product\DLLs
C:\Work\build\product\lib
C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO\2017\PROFESSIONAL\COMMON7\IDE\EXTENSIONS\TESTPLATFORM
C:\Users\rvq\AppData\Roaming\Python\Python37\site-packages
检查 sys.path 的内容我注意到两件事。
C:\Work\build\product\python37.zip 具有正确的路径“C:\Work\build\product\'”。只是没有 zip 文件。我所有的文件和目录都被解压了。所以我将文件压缩到一个名为 python37.zip 的存档中,这解决了导入错误。
C:\Users\rvq\AppData\Roaming\Python\Python37\site-packages 错了应该是C:\Work\build\product\Lib\site-packages 但我不知道这个错误的路径是如何创建的。
接下来我尝试的是在调用Py_Initialize() 之前使用Py_SetPath(L"C:/Work/build/product/Lib/site-packages")。这导致了
致命的 Python 错误“无法加载文件系统编码”
ModuleNotFoundError: 没有名为“编码”的模块
我用这两个调用创建了一个最小的 c++ 项目并开始调试 Cpython。
int main()
{
Py_SetPath(L"C:/Work/build/product/Lib/site-packages");
Py_Initialize();
}
我追踪了Py_Initialize() 的电话直到
static int
zipimport_zipimporter___init___impl(ZipImporter *self, PyObject *path)
zipimport.c 内部
此函数上方的注释说明如下:
创建一个新的 zipimporter 实例。 'archivepath' 必须是类似路径的
对象到 zipfile 或 zipfile 中的特定路径。为了
例如,它可以是“/tmp/myimport.zip”,或者
'/tmp/myimport.zip/mydirectory',如果 mydirectory 是有效目录
档案馆内。如果“归档路径”,则会引发“ZipImportError”
不指向有效的 Zip 存档。的“存档”属性
zipimporter 对象包含目标压缩文件的名称。
所以对我来说,C-API 似乎希望使用 Py_SetPath 设置的路径是 zipfile 的路径。这是预期的行为还是错误?
如果它不是一个错误,有没有办法改变它,以便它也可以检测目录?
PS:我在使用 Python 3.5.2+ 时没有出现 ModuleNotFoundError,这是我之前在项目中使用的版本。我还检查了是否设置了任何 PYTHONHOME 或 PYTHONPATH 环境变量,但我没有在我的系统上看到它们。
回答
这可能是一个文档失败,而不是其他任何事情。不过,我们正在重新设计初始化,因此现在是提供此反馈的好时机。
简短的回答是,您需要确保 Python 可以找到 Lib/encodings 目录,通常是将标准库放在 sys.path 中。 Py_SetPath 清除所有推断的路径,因此您需要指定 Python 应该查找的所有位置。 (Python 自动显示的规则很复杂,并且因平台而异,这是我很想解决的问题。)
不存在的路径是可以的,那就是 zip 文件。您可以选择将stdlib压缩成一个zip,如果您将其命名为默认路径,它将自动找到,但您也可以将其解压缩并引用目录。
全面了解嵌入比我准备在手机上输入的内容要多。希望这足以让您暂时继续前进。