我有同样的问题,发现了这个问题。但是从这里的答案我无法解决我的问题。我开始调试cpython代码,并认为可能会发现我的错误。因此,我在python问题跟踪器上打开了一个问题。
我的错误是我不明白这会Py_SetPath清除所有推断的路径。因此,在调用此函数时,需要设置所有路径。
为了完整起见,我还复制了下面对话的最重要部分。
我的原始问题文字
我自己在Windows上使用Visual Studio 2017编译了CPython 3.7.3的源代码以及一些软件包,例如numpy。当我启动Python解释器时,我能够导入并使用numpy。但是,当我通过C-API运行相同的脚本时,ModuleNotFoundError。
因此,我要做的第一件事是检查numpy是否在我的site-packages目录中,并且确实存在一个名为numpy-1.16.2-py3.7-win-amd64.egg的文件夹。(之所以有意义是因为python解释器可以找到numpy)
我要做的下一件事是获取有关通过C-API运行脚本时创建的sys.path变量的一些信息。
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\'。没有压缩文件。我所有的文件和目录都已解压缩。因此,我将文件压缩到名为python37.zip的存档中,这解决了导入错误。
C:\Users\rvq\AppData\Roaming\Python\Python37\site-packages应该是错的,C:\Work\build\product\Lib\site-packages但我不知道如何创建错误的路径。
我尝试的下一件事情是Py_SetPath(L"C:/Work/build/product/Lib/site-packages")在致电之前使用Py_Initialize()。这导致
致命的Python错误“无法加载文件系统编码” ModuleNotFoundError:没有名为“ encodings”的模块
我使用这两个调用创建了一个最小的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中特定路径的类似路径的对象。例如,如果mydirectory是归档文件中的有效目录,则可以是“ /tmp/myimport.zip”或“ /tmp/myimport.zip/mydirectory”。如果“ archivepath”未指向有效的Zip存档,则引发“ ZipImportError”。zipimporter对象的'archive'属性包含目标zipfile的名称。
因此,对于我来说,似乎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文件中,如果将其命名为默认路径,则会自动找到该文件,但也可以将其解压缩并引用目录。
完整的嵌入过程远远超过了我准备在手机上键入的内容。希望这足以让您现在就出发。