是否可以在運行時修改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:



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):


int main(int argc, char* argv[])
  _putenv_s("PYTHONPATH", "C:\\source\\\\modules");
  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?


7 个解决方案



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


import sys



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.




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上)。


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




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");
  PyRun_SimpleString("import sys\nprint sys.path");
  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.:



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



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加載它,看看這是否會改變什么。



#include "Python.h"
int main()
  PyRun_SimpleString("import sys");
  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:


  • 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.




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

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



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