はじめに
これまでC#とPythonの連携について似たようなネタをいくつか書いてきた。
「C# GUIアプリケーションからPythonスクリプトを実行する」では、Pythonスクリプトを実行し、処理が終了するまで進捗状況を確認できるようにした。
「C# GUIからPythonのコードを実行する」では、Pythonスクリプトではなく、画面上からPythonコードを入力できるようにしてみた。
そして「C# GUIからバックグラウンドでプロセスを実行し管理する」では、Pythonを実行した後、終了まで待たずに別の作業をしつつ、気になったときに実行状況を確認できる方法について調べた。
そこで、今回がこのシリーズ最後のネタになる。
そもそもGUIなんかいらんから、Pythonのスクリプトを実行して、その処理結果を受け取るようなメソッドとか作りたいんだけど、どうすんの?
要するにGUIを介さず、Pythonスクリプトを開始し、実行が終わるまで次の処理に行かずにそこで待ち(同期をとる)、その後結果を取得するという形の呼び出しだ。
ソース
はい、どん。
PythonExecutor.cs
usingSystem;usingSystem.Diagnostics;usingSystem.IO;usingSystem.Text;namespaceChemShow{publicclassPythonExecutor{publicStringFileName{get;set;}publicStringWorkingDirectory{get;set;}publicStringArguments{get;set;}publicStringInputString{get;set;}publicStringStandardOutput{get;set;}publicintExitCode{get;set;}privateStringBuilderstandardOutputStringBuilder=newStringBuilder();publicPythonExecutor(){}/// 実行ボタンクリック時の動作publicvoidExecute(){ProcessStartInfopsInfo=newProcessStartInfo();psInfo.FileName=this.FileName;psInfo.WorkingDirectory=this.WorkingDirectory;psInfo.Arguments=this.Arguments;psInfo.CreateNoWindow=true;psInfo.UseShellExecute=false;psInfo.RedirectStandardInput=true;psInfo.RedirectStandardOutput=true;psInfo.RedirectStandardError=true;Processp=Process.Start(psInfo);p.OutputDataReceived+=p_OutputDataReceived;p.ErrorDataReceived+=p_ErrorDataReceived;// プロセスの実行p.Start();// 標準入力への書き込みusing(StreamWritersw=p.StandardInput){sw.Write(InputString);}//非同期で出力とエラーの読み取りを開始p.BeginOutputReadLine();p.BeginErrorReadLine();// 終わるまでまつp.WaitForExit();this.ExitCode=p.ExitCode;this.StandardOutput=standardOutputStringBuilder.ToString();}/// <summary>/// 標準出力データを受け取った時の処理/// </summary>voidp_OutputDataReceived(objectsender,System.Diagnostics.DataReceivedEventArgse){//processMessage(sender, e);if(e!=null&&e.Data!=null&&e.Data.Length>0){standardOutputStringBuilder.Append(e.Data+"\n");}}/// <summary>/// 標準エラーを受け取った時の処理/// </summary>voidp_ErrorDataReceived(objectsender,System.Diagnostics.DataReceivedEventArgse){//必要な処理を書く}}}ソース解説
目新しいことはなく、プロセスを開始したらそのままWaitForExit()を実行しているだけ。そうするとプロセスが終了するまで次にいかない。これにより同期的な呼び出しが実現できる。実行終了後、終了コードや標準出力のデータをプロパティから取得できるようにしている。
使い方
以下はスクリプトの標準入力にデータを与え、標準出力に出力された結果を受け取る例である。
PythonExecutorpe=newPythonExecutor();pe.FileName=@"c:\python3.6\bin\python.exe";pe.WorkingDirectory=@"c:\tmp";pe.Arguments=@"C:\ChemShow\python\hist.py";pe.InputString="1,2,3,4,5,6,7,8,9,10";//標準入力に与えるデータpe.Execute();//実行Console.WriteLine(pe.StandardOutput);//標準出力の結果を出力おわりに
要するに、今までに出てきた全ての呼び出し方に対応したコンポーネントをいい加減作れよという話。
後、タイトルはPythonスクリプトにしているが、コマンドラインから実行できるものであれば同じですね。