10

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 - 私の目標を達成する他の方法があることは知っていますが、それは私が求めているものではありません. sys.path を設定するときに Py_Initialize() が PYTHONPATH の現在の値を使用しないのはなぜでしょうか。それとも、それがどのように機能するかを誤解していますか?

4

7 に答える 7

11

クロスプラットフォーム ソリューションを見つけました。他の Python コードを呼び出す前に、次の Python 行を実行してください。

import sys
sys.path.append("C:\\source\\\\modules")
于 2011-11-18T18:55:18.280 に答える
3

これは、一度に複数の C ランタイム ライブラリを使用している場合に発生します。この場合、アプリケーションと Python DLL はおそらく異なる CRT に対してリンクされています。各 CRT には、独自の環境変数のセットがあります。ある CRT から putenv で行われた環境への変更は、別の CRT で行われた getenv 呼び出しからは見えません。

http://msdn.microsoft.com/en-us/library/ms235460%28v=vs.80%29.aspxの「readEnv」の例を参照してください。

これは、CRT を 1 つだけ使用するようにすることで解決できますが、実際には注意が必要です。プログラムのデバッグ ビルドは、通常、デバッグ CRT (ヒープ チェックや API アサーションなどを有効にします) を使用します。実稼働 DLL は、デバッグで使用される場合でも、通常、実稼働のスレッドセーフ バージョンである MSVCRT を使用します。個別のデバッグ DLL を維持するのは面倒なので、デバッグ CRT を完全に無効にし、すべてのビルドを「マルチスレッド ダイナミック」に設定することで、この問題を回避しました。そうすることで、一部のデバッグ機能が失われます。

于 2011-03-16T00:12:14.217 に答える
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:\\', ...
于 2011-03-16T04:23:40.933 に答える
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を使用する必要があります。Windows パス区切り文字を UNIX 区切り文字に置き換えることをお勧めします。次のコードチャンクがこれを行います。

    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 で導入されましたが、バグがあります ( http://bugs.python.org/issue11320を参照) 。

一般に、上記の API メソッドは afterPy_Initialize()呼び出しには影響しません。

于 2015-05-05T04:53:43.260 に答える
1

Python DLL が読み込まれると、環境の独自のコピーを取得する可能性があります。環境を変更した後、LoadLibrary と GetProcAddress を使用してロードしてみて、何かが変わるかどうかを確認してください。

于 2011-03-16T03:20:39.003 に答える