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行を入れてください。
using System.Diagnostics;
Pythonを呼び出す関数(メソッド)は次の様になります。
第一引数はPythonのプログラムファイルのパス、第2引数はPythonプログラムに渡す引数です。
Pythonプログラムに複数の引数を渡す場合は、半角スペースで区切ってください。
例えば、Eドライブのルートに存在するPythonTest.py というプログラムに、"hoge" 123 3.14 という3つの引数を渡したい場合は、次の様になります。
PythonCall("E:\PythonTest.py","hoge 123 3.14");
/// <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ループで全て取り出します。
//Pythonプログラムを実行し、戻ってきた結果をテキストボックスに出力
foreach(string line in PythonCall("E:\PythonTest.py","hoge 123 3.14"))
{
uxResult.AppendText(line);
}
参考までに、Pyton側のサンプルも載せておきます。
これは今回デモプログラムから呼び出しているPythonプログラムの内容です。
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行目を次のように変更してください。
// 変更前
psInfo.FileName = "Python";
// 変更後
psInfo.FileName = "conda activate MyEnv & Python";
まとめ
ProcessStartを使うと、いとも簡単にC#側から任意のPythonプログラムを呼び出し、結果を受け取れます。
今回紹介した方法の利点は、何といってもPython側に特別な考慮が不要という事です。
Python側はPython単体でデバッグできますので、他の方法に比べて相互の依存度が低く、各段に扱いやすくなります。
C#で出来ない事、やりにくい事はPython側に任せて、効率よくプログラムを作っていきましょう。
コメント