Можно ли изменить PYTHONPATH во время выполнения?
У меня есть приложение C++, динамически связанное с интерпретатором Python. Я хочу иметь возможность импортировать модули Python из определенного каталога. Я хочу изменить PYTHONPATH для моего процесса, чтобы sys.путь будет включать пути, которые я добавил к PYTHONPATH. Похоже, что это работает в соответствии с этой документацией:
http://docs.python.org/c-api/intro.html#embedding-python
однако, когда я печатаю sys.путь из страны Python он имеет оригинальное содержание PYTHONPATH и не один я. Вот пример того, что я делаю (используя Boost.Python):
int main(int argc, char* argv[])
{
_putenv_s("PYTHONPATH", "C:source\modules");
Py_Initialize();
object main = import("__main__");
object global = (main.attr("__dict__"));
exec("import sysnprint sys.path"), global, global);
}
PS - Я знаю, что есть другие способы достижения моей цели, но это не то, что я прошу об. Мне интересно, почему Py_Initialize () не использует текущее значение PYTHONPATH при настройке sys.путь. Или, возможно, я неправильно понял, как это должно работать?
7 ответов
Я нашел кросс-платформенное решение. Перед вызовом любого другого кода python просто выполните следующие строки python:
import sys
sys.path.append("C:\source\\modules")
Это происходит, если вы используете более одной библиотеки времени выполнения C. В этом случае ваше приложение и DLL Python, вероятно, связаны с различными CRTs. Каждая ЭЛТ имеет свой собственный набор переменных среды; изменения в среде, сделанные с помощью putenv из одной ЭЛТ, не видны из вызовов getenv, сделанных с другой ЭЛТ.
см. пример "readEnv" вhttp://msdn.microsoft.com/en-us/library/ms235460%28v=vs.80%29.aspx.
вы можно исправить это, убедившись, что используется только один ЭЛТ, но это сложно на практике. Отладочные сборки программ обычно используют отладочные CRT (которые включают такие вещи, как проверки кучи и утверждения API); производственные библиотеки DLL, даже когда они используются в отладке, обычно используют MSVCRT, производственную, потокобезопасную версию. Я работал вокруг этого, полностью отключив отладочные CRTs, установив все сборки на "многопоточную динамику", так как поддержание отдельных отладочных DLL-библиотек слишком много хлопот. Вы теряете некоторую отладку возможности делать это.
Проверьте:
void PySys_SetPath (char * path) установить sys.путь к объекту списка путей, найденных в path, который должен быть списком путей, разделенных разделителем пути поиска платформы (: в Unix, ; в Windows).
или
Py_SetProgramName(argv[0]); это добавляет dirname (argv[0]) к вашему PYTHONPATH для вас.
как говорили другие люди, Вы можете столкнуться с несоответствием CRT. Я смог заставить это работать с Python 2.6 и Visual C++ 2008:
#include "stdafx.h"
#include "Python.h"
int _tmain(int argc, _TCHAR* argv[])
{
_putenv_s("PYTHONPATH", "C:\source\\modules");
Py_Initialize();
PyRun_SimpleString("import sys\nprint sys.path");
PyRun_SimpleString("raw_input()");
return 0;
}
этот вывод:
['C:\Python26\lib\site-packages\distribute-0.6.13-py2.6.egg', 'C:\Python26\
\lib\site-packages\virtualenv-1.4.9-py2.6.egg', 'C:\source\modules', ...
другим вариантом может быть изменение в этот каталог, так как текущий каталог обычно заканчивается на пути, например:
_chdir("c:\");
Py_Initialize();
[...]
что дает мне:
['C:\Python26\lib\site-packages\distribute-0.6.13-py2.6.egg', 'C:\Python26\
\lib\site-packages\virtualenv-1.4.9-py2.6.egg', 'C:\Windows\system32\python
26.zip', 'C:\Python26\Lib', 'C:\Python26\DLLs', 'C:\Python26\Lib\lib-tk',
'c:\', ...
возможно, что DLL Python получает свою собственную копию среды при ее загрузке. Попробуйте загрузить его с помощью LoadLibrary и GetProcAddress после того, как вы изменили среду, и посмотрите, изменится ли что-нибудь.
#include "Python.h"
int main()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"<some_path>\")");
return 0;
}
это работает для всех версии Python (2.6, 2.7, 3.1, 3.2, 3.3 и 3.4).
Несколько заметок относительно <some_path>
:
- он должен содержать только один