У меня была такая же проблема, и я нашел этот вопрос. Однако из ответов здесь я не смог решить мою проблему. Я начал отлаживать код cpython и подумал, что я могу обнаружить ошибку. Поэтому я открыл проблему на трекере Python.
Моя ошибка состояла в том, что я не понял, что Py_SetPath
очищает все предполагаемые пути.
Таким образом, нужно указать все пути при вызове этой функции.
Для завершения я также скопировал самую важную часть беседы ниже.
Мой оригинальный текст вопроса
Я сам скомпилировал исходники CPython 3.7.3 для Windows с Visual Studio 2017 вместе с некоторыми пакетами, например, например, numpy. Когда я запускаю Python Interpreter, я могу импортировать и использовать numpy. Однако, когда я запускаю тот же сценарий через C-API, я получаю ModuleNotFoundError
.
Итак, первое, что я сделал, это проверил, находится ли numpy в моем каталоге site-packages и действительно ли там есть папка с именем numpy-1.16.2-py3.7-win-amd64.egg. (Имеет смысл, потому что интерпретатор Python может найти NumPy)
Следующее, что я сделал, было получить некоторую информацию о переменной sys.path, созданной при запуске скрипта через C-API.
#### 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\'
. Там просто не было почтового файла. Все мои файлы и каталог были распакованы. Поэтому я заархивировал файлы в архив с именем 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' должен быть похож на путь
объект к zip-файлу или к определенному пути внутри zip-файла. За
Например, это может быть /tmp/myimport.zip или
'/tmp/myimport.zip/mydirectory', если mydirectory является допустимым каталогом
внутри архива. 'ZipImportError' возникает, если 'archivepath'
не указывает на действительный Zip-архив. Атрибут «архив»
Объект zipimporter содержит имя целевого файла zipfile.
Так что для меня кажется, что C-API ожидает, что путь, заданный с помощью Py_SetPath, будет путем к zip-файлу. Это ожидаемое поведение или это ошибка?
Если это не ошибка, есть ли способ изменить это так, чтобы он также мог обнаруживать каталоги?
PS: ModuleNotFoundError не возникла у меня при использовании Python 3.5.2+, который я использовал в своем проекте ранее. Я также проверил, установил ли я какие-либо переменные окружения PYTHONHOME или PYTHONPATH, но не увидел ни одной из них в своей системе.
Ответ
Вероятно, это сбой документации больше всего на свете. Мы сейчас находимся в процессе реорганизации инициализации, так что самое время подать этот отзыв.
Короткий ответ: вам нужно убедиться, что Python может найти каталог Lib/encodings
, обычно помещая стандартную библиотеку в sys.path
. Py_SetPath
очищает все выведенные пути, поэтому вам нужно указать все места, которые Python должен искать. (Правила того, как Python выглядит автоматически, сложны и различаются в зависимости от платформы, и я очень хочу это исправить.)
Пути, которые не существуют, в порядке, и это zip-файл.Вы можете поместить stdlib в zip-файл, и он будет найден автоматически, если вы назовете его по умолчанию, но вы также можете оставить его разархивированным и сослаться на каталог.
Полный обзор встраиваниябольше, чем я готов набрать на моем телефоне.Надеюсь, этого достаточно, чтобы вы пошли сейчас.