我有一个动态链接到Python解释器的C ++应用程序。我希望能够从特定目录导入python模块。我想修改我的进程的PYTHONPATH,以便sys.path将包含我添加到PYTHONPATH的路径。这似乎是根据这个文档的工作方式:
http://docs.python.org/c-api/intro.html#embedding-python
然而,当我从Python-land打印sys.path时,它具有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 sys\nprint sys.path"), global, global);
}
PS - 我知道还有其他方法可以实现我的目标,但这不是我所要求的。我想知道为什么Py_Initialize()在设置sys.path时不使用PYTHONPATH的当前值。或许我误解了它应该如何运作?
答案 0 :(得分:7)
我发现了跨平台解决方案。在调用任何其他python代码之前,只需执行以下python行:
import sys
sys.path.append("C:\\source\\\\modules")
答案 1 :(得分:3)
如果您一次使用多个C运行时库,则会发生这种情况。在这种情况下,您的应用程序和Python DLL可能与不同的CRT相关联。每个CRT都有自己的一组环境变量;使用不同CRT进行的getenv调用无法看到使用putenv从一个CRT进行的环境变化。
请参阅http://msdn.microsoft.com/en-us/library/ms235460%28v=vs.80%29.aspx上的“readEnv”示例。
你可以通过确保只使用一个CRT来解决这个问题,但这在实践中很棘手。程序的调试版本通常使用调试CRT(它支持诸如堆检查和API断言之类的事情);生产DLL,即使在调试中使用,通常也使用MSVCRT,即生产线程安全版本。我通过完全禁用调试CRT,将所有构建设置为“多线程动态”来解决这个问题,因为维护单独的调试DLL太麻烦了。这样做会失去一些调试功能。
答案 2 :(得分:3)
退房:
void PySys_SetPath(char * path)将sys.path设置为路径中找到的路径的列表对象,该路径应该是使用平台的搜索路径分隔符分隔的路径列表(:在Unix上,在Windows上)。
或
Py_SetProgramName(argv的[0]);这会为您的PYTHONPATH添加dirname(argv [0])。
答案 3 :(得分:2)
正如其他人所说,您可能遇到了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:\\', ...
答案 4 :(得分:1)
Python DLL有可能在加载时获得自己的环境副本。在更改环境后,尝试使用LoadLibrary和GetProcAddress加载它,看看是否有任何改变。
答案 5 :(得分:1)
#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>
的几点说明:
d:/path1;d:/path2
等)的目录列表无效 Windows路径如:d:\\path1
仅适用于Python 3之前的python版本,因为应使用更高版本d:\\\\path1
。我建议用unix分隔符替换windows路径分隔符。以下代码块执行此操作。
std::string my_path = "<some_path>";
std::replace(my_path.begin(), my_path.end(), '\\', '/');
温和的建议: 如果您想支持不同的python版本,请不要浪费时间尝试使用以下任一API方法修改PYTHONPATH:
Py_SetPythonHome()
- 对于python 2,需要一个ascii字符串,对于python 3 - 一个unicode字符串,但对于大于3.1的版本不能可靠地工作Py_SetPath()
- 在python 3中引入,但是有bug(参见http://bugs.python.org/issue11320)通常,上面列出的API方法在Py_Initialize()
调用后不会影响。
答案 6 :(得分:1)
您可以python3 -c "import sys; sys.path.append('C:\Path\To\Modules')"