AIブームの昨今、Pythonが人気沸騰中です。
しかしながら、画面操作を伴うようなプログラムはPythonだと非効率ですよね。
そこで、入力操作はWindowsFormやWPFによる画面を使い、そこから必要な時にPythonを呼び出して、結果を受け取れたら便利ですね。
ということで、今回は簡単に組み込める関数化(メソッド化)してみました。
今回はデモプログラムを用意していますので、いろいろと試してみて下さい。
デモプログラムはWindowsForm で作ってますが、Python呼び出し部分はWPFでも共通で使えます。
デモプログラムの概要
「実行」ボタンをクリックすると
- 画面のテキストボックスに表示されているPythonプログラムをファイルに書き込む
- 書き込んだPythonプログラムを実行する
- 実行中にPythonプログラムが出力した結果(文字列)をリアルタイムに画面表示する
というものです。
サンプルのダウンロード
下記から一式ダウンロードできます。(2021/09/28 一部不具合を修正しました)
C#からPythonを呼び出すデモプログラム一式
C#からPythonを呼び出す3つの方法
ネットで調べてみると、次の3種類がありました。
今回は一番互換性が高く一番楽なProcessStartを使います。
方法 | 解説 |
---|---|
pythonnet | Nugetからpythonnetをインストールすることで、C#からPythonが呼び出せる。 Python側も用意されていて、そちらをつかうとPythonからC#を呼び出すことが可能。 どちらかと言うと、C#の中で任意のPythonコードを実行するようなイメージ。 それなりにゴリゴリと記述しないと使えない。 |
IronPython | .NET Framework上で動くPythonであるため、C#とPythonの相互で情報のやり取りが出来る。 ただし、普通に使われているPythonとは少し違うので、100%互換性は無い。 |
ProcessStart | C#から外部プロセスを実行するための方法を用いて、Python環境ごとPythonプログラム動かす。 Pythonのバージョンを選ばず、また普通にPythonのコードを書いてC#から実行可能。 C#側も簡単なコードを書くだけで済むので、一番敷居低い。 |
実際のC#側のコード
では、さっそくソースコードを掲載します。
まず、冒頭の参照設定に次の1行を入れてください。
1 |
using System.Diagnostics; |
Pythonを呼び出す関数(メソッド)は次の様になります。
第一引数はPythonのプログラムファイルのパス、第2引数はPythonプログラムに渡す引数です。
Pythonプログラムに複数の引数を渡す場合は、半角スペースで区切ってください。
例えば、Eドライブのルートに存在するPythonTest.py というプログラムに、"hoge" 123 3.14 という3つの引数を渡したい場合は、次の様になります。
PythonCall("E:\PythonTest.py","hoge 123 3.14");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/// <summary> /// プロセスの実行 /// </summary> /// <param name="filename"></param> /// <param name="args"></param> /// <returns></returns> public IEnumerable<string> PythonCall(string program,string args = "") { ProcessStartInfo psInfo = new ProcessStartInfo(); // 実行するファイルをセット psInfo.FileName = "Python"; //引数をセット psInfo.Arguments = string.Format("\"{0}\" {1}", program, args); // コンソール・ウィンドウを開かない psInfo.CreateNoWindow = true; // シェル機能を使用しない psInfo.UseShellExecute = false; // 標準出力をリダイレクトする psInfo.RedirectStandardOutput = true; // プロセスを開始 Process p = Process.Start(psInfo); // アプリのコンソール出力結果を全て受け取る string line; while ((line = p.StandardOutput.ReadLine()) != null) { yield return line + Environment.NewLine; } } |
Python側からC#側に返したい値は、コンソール出力します。
Python側でコンソール出力した結果は、C#側から1行ずつ取得できますので、Forループで全て取り出します。
1 2 3 4 5 |
//Pythonプログラムを実行し、戻ってきた結果をテキストボックスに出力 foreach(string line in PythonCall("E:\PythonTest.py","hoge 123 3.14")) { uxResult.AppendText(line); } |
参考までに、Pyton側のサンプルも載せておきます。
これは今回デモプログラムから呼び出しているPythonプログラムの内容です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import sys argvs = sys.argv message = argvs[1] count = int(argvs[2]) print('開始') for i in range(count): print('{0} {1}'.format(message,i)) print('完了') |
CONDA の仮想環境でPythonを実行する場合
Anacondaでは仮想環境を使って複数のPython環境を管理することができます。
もし特定の仮想環境でPythonプログラムを呼び出したい場合は、Python を呼び出す直前に conda activate で仮想環境を切り替えるコマンドを実行する必要があります。
conda activate 仮想環境名 & Python
&を使うことで 2つのコマンドを連続実行することができます。
もし仮想環境名が MyEnv の場合、サンプルソースの11行目を次のように変更してください。
1 2 3 4 5 |
// 変更前 psInfo.FileName = "Python"; // 変更後 psInfo.FileName = "conda activate MyEnv & Python"; |
まとめ
ProcessStartを使うと、いとも簡単にC#側から任意のPythonプログラムを呼び出し、結果を受け取れます。
今回紹介した方法の利点は、何といってもPython側に特別な考慮が不要という事です。
Python側はPython単体でデバッグできますので、他の方法に比べて相互の依存度が低く、各段に扱いやすくなります。
C#で出来ない事、やりにくい事はPython側に任せて、効率よくプログラムを作っていきましょう。
コメント