是否可以在运行时修改PYTHONPATH ?

[英]Is it possible to modify PYTHONPATH at runtime?


I have a C++ application dynamically linked to the Python interpreter. I want to be able to import python modules from a particular directory. I want to modify the PYTHONPATH for my process so that sys.path will include the paths that I added to the PYTHONPATH. That seems to be the way it works according to this documentation:

我有一个动态链接到Python解释器的c++应用程序。我希望能够从一个特定的目录导入python模块。我想要为我的进程修改PYTHONPATH,这样系统。path将包含我添加到PYTHONPATH中的路径。这似乎是它的工作方式根据这个文件:

http://docs.python.org/c-api/intro.html#embedding-python

http://docs.python.org/c-api/intro.html embedding-python

However, when I print sys.path from Python-land it has the original contents of PYTHONPATH and not the one I set. Here's an example of what I'm doing (using Boost.Python):

但是,当我打印sys时。它包含了PYTHONPATH的原始内容,而不是我设置的。

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 - I know there are other ways to accomplish my goal, but that's not what I'm asking about. I am wondering why Py_Initialize() doesn't use the current value of PYTHONPATH when setting up sys.path. Or perhaps I've misunderstood how it is supposed to work?

我知道还有其他方法可以实现我的目标,但这不是我想要的。我想知道为什么Py_Initialize()在设置sys.path时不使用PYTHONPATH的当前值。或许我误解了它的工作原理?

7 个解决方案

#1


7  

I found cross-platform solution. Before invoke any other python code just execute following python lines:

我发现跨平台解决方案。在调用任何其他python代码之前,请执行以下python行:

import sys
sys.path.append("C:\\source\\\\modules")

#2


3  

This happens if you're using more than one C runtime library at a time. In this case, your application and the Python DLL are probably linked against different CRTs. Each CRT has its own set of environment variables; changes to the environment made with putenv from one CRT are not visible from getenv calls made with a different CRT.

如果一次使用多个C运行时库,就会发生这种情况。在这种情况下,您的应用程序和Python DLL可能被链接到不同的crt上。每个CRT都有自己的环境变量集;使用一个CRT对putenv进行的环境更改从使用另一个CRT进行的getenv调用中看不到。

See the "readEnv" example at http://msdn.microsoft.com/en-us/library/ms235460%28v=vs.80%29.aspx.

请参见http://msdn.microsoft.com/en- us/library/ms2354600% 28v=vs.8029.aspx的“readEnv”示例。

You can fix this by making sure to use only a single CRT, but that's tricky in practice. Debug builds of programs typically use debug CRTs (which enable things like heap checks and API assertions); production DLLs, even when used in debugging, typically use MSVCRT, the production, threadsafe version. I've worked around this by disabling the debug CRTs entirely, setting all builds to "multithreaded dynamic", since maintaining separate debug DLLs is too much of a hassle. You lose some debugging capabilities by doing that.

您可以通过确保只使用一个CRT来解决这个问题,但这在实践中是很棘手的。程序的调试构建通常使用调试crt(它支持堆检查和API断言);生产dll,即使在调试中使用,通常也使用MSVCRT,即生产的threadsafe版本。我通过完全禁用调试crt来解决这个问题,将所有的构建设置为“多线程动态”,因为维护单独的调试dll实在是太麻烦了。这样做会丢失一些调试功能。

#3


3  

Check out:

查看:

void PySys_SetPath(char *path) Set sys.path to a list object of paths found in path which should be a list of paths separated with the platform’s search path delimiter (: on Unix, ; on Windows).

void PySys_SetPath(char *path)路径中找到的路径列表对象的路径,该路径应该是与平台的搜索路径分隔符(:Unix上;在Windows上)。

or

Py_SetProgramName(argv[0]); That adds dirname(argv[0]) to your PYTHONPATH for you.

Py_SetProgramName(argv[0]);它为您将dirname(argv[0])添加到python路径中。

#4


2  

As other people have said, you may be running into a CRT mismatch. I was able to get this to work with Python 2.6 and Visual C++ 2008:

正如其他人所说,您可能会遇到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;
}

This output:

这个输出:

['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', ...

Another option may be to change to that directory, since the current directory typically ends up on the path, e.g.:

另一种选择可能是更改到该目录,因为当前目录通常在路径上结束,例如:

    _chdir("c:\\");
    Py_Initialize();
[...]

which gives me:

给我:

['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:\\', ...

#5


1  

It is possible that the Python DLL gets its own copy of the environment when it is loaded. Try loading it with LoadLibrary and GetProcAddress after you've changed the environment and see if that changes anything.

在加载环境时,Python DLL可能获得它自己的环境副本。在更改了环境之后,尝试使用LoadLibrary和GetProcAddress加载它,看看这是否会改变什么。

#6


1  

#include "Python.h"
int main()
{
  Py_Initialize();
  PyRun_SimpleString("import sys");
  PyRun_SimpleString("sys.path.append(\"<some_path>\")");
  return 0;
}

This worked for all python version (2.6, 2.7, 3.1, 3.2, 3.3 and 3.4).
Several notes regarding <some_path>:

这适用于所有python版本(2.6、2.7、3.1、3.2、3.3和3.4)。一些笔记关于< some_path >:

  • It should contain only a single directory. List of directories with valid separators (d:/path1;d:/path2 etc.) is not working
  • 它应该只包含一个目录。有有效分隔符的目录列表(d:/path1;d:/path2等)无效
  • Windows paths like: d:\\path1 will work only for python versions prior to Python 3, for later versions d:\\\\path1 should be used. I'd advice replacing windows path delimiters with unix delimiters. Following code chunk does this.

    Windows路径如:d:\ path1只适用于python 3之前的python版本,适用于以后的版本d:\\\ path1。我建议用unix分隔符替换windows路径分隔符。下面的代码块可以做到这一点。

    std::string my_path = "<some_path>"; std::replace(my_path.begin(), my_path.end(), '\\', '/');

    std::string my_path = " < some_path >”;std::替换(my_path.begin(),my_path.end(),' \ \ ',' / ');

A gentle advise: Don't waste your time trying to modify PYTHONPATH with either of the following API methods if you want to support different python versions:

一个温和的建议:如果您希望支持不同的python版本,请不要浪费时间尝试使用以下任何一种API方法修改PYTHONPATH:

  • Py_SetPythonHome() - for python 2 requires an ascii string, for python 3 - a unicode string, but doesn't work reliably for versions greater than 3.1
  • Py_SetPythonHome()——对于python 2,需要一个ascii字符串;对于python 3,需要一个unicode字符串;但是对于大于3.1的版本,它不能可靠地工作
  • Py_SetPath() - introduced in python 3, but is buggy (see http://bugs.python.org/issue11320)
  • Py_SetPath()——在python 3中引入,但是有bug(参见http://bugs.python.org/issue11320)

In general API methods listed above do not affect after Py_Initialize() call.

在一般情况下,上面列出的API方法不会影响Py_Initialize()调用之后的API。

#7


1  

You could just do python3 -c "import sys; sys.path.append('C:\Path\To\Modules')"

你可以用python3 -c "import sys;sys.path.append(“C:\路径\ \模块”)”


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2011/03/15/c0e041cebf77b53c2529a62921dcc7cf.html



 
  © 2014-2022 ITdaan.com 联系我们: