C#.NETからPythonのスクリプトファイルを実行するサンプルです。使用しているのはpythonnetです。他にクラスProcessでコントロールする方法もありますが、pythonnetの方が記述がすっきりしているので、こっちを使ってます。
ユーザーが作成したpythonのスクリプトを実行させて、そのレスポンスを取得できます。下のようにPython.Runtime.dllを間に挟んで相互のやり取りをしています。
exe → Python.Runtime.dll → Python.dll
Pythonnetの導入とVisualStudioの設定
設定は、たった二か所だけです。
Pythonnetのインストール
- VisualStudioのメニュー → ツール → NuGetパッケージマネージャ → ソリューションのNuGetパッケージ管理で管理画面を開きます。
- 参照を選択
- pythonnet_netstarndardで検索
- インストール
非推奨のものを避け、pythonnet_netstandard_py38_winを入れました。
VisualStudioのソリューションの設定
デフォルトは、”Any CPU”になっていますが、Pythonに合わせ64bitにします。構成マネージャで、アクティブソリューションプラットフォームをx64に設定すると、64bitになります。
C#.NETからpyファイルを呼び出すサンプル
サンプルのため非常にシンプルなソースですが、設定の自由度は高くなっています。
Pythonのスクリプトファイル 呼び出される側
hogehoge.pyのfoo()が呼ばれます。
# hogehoge.py
def foo(val):
val += 5
return f"result {val}"
if __name__ == '__main__':
foo(12)
C# 呼び出し元
using System;
using System.Windows.Forms;
using Python.Runtime;
using System.IO;
namespace CallPython
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// モジュールのあるパスを追加
// exeのあるフォルダは、追加不要
string[] pathes = {
PythonEngine.PythonPath,
Path.Combine(@"~") //< Python Script ファイルのあるフォルダを設定
};
PythonEngine.PythonPath = string.Join(Path.PathSeparator.ToString(), pathes);
Console.WriteLine(PythonEngine.PythonPath);
PythonEngine.Initialize();
// Pythonのオブジェクト取得・操作前にロックが必要
IntPtr pythonLock = PythonEngine.AcquireLock();
// モジュールの実行と戻り値の取得
PyDict pyDict = new PyDict();
PythonEngine.Exec("import hogehoge", locals: pyDict.Handle);
var ret = PythonEngine.Eval("hogehoge.foo(58)", locals: pyDict.Handle);
Console.WriteLine(ret);
PythonEngine.ReleaseLock(pythonLock);
PythonEngine.Shutdown();
}
}
}
PythonEngine.PythonPathは、実行したいpythonモジュールのあるフォルダを設定します。.NETの実行バイナリのフォルダはデフォルトでパスが通っているため、exeと同じフォルダににPythonのモジュールを配置すればPythonPathを設定する必要はありません。
実行結果
'CallPython.exe' (CLR v4.0.30319: CallPython.exe): '__CodeGenerator_Assembly' が読み込まれました。 result 63
戻り値の受け取り
python側から文字列を得られるので、JSONも使えます。


