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も使えます。
コメント