Pythonから.NET向けのDLLを使う~Python for .NET~
最近、面白がって Python for .NET | pythonnet.github.ioを使ってアプリケーションの開発をしていたのでその雑記です。
想定パターン
とりあえず、以下のようなケースで利用出来そう。
.NET向けのDLLをPythonで利用したいとき
アプリケーションの本体がPython側で、.NETのDLLなどを弄る必要がある場合に使える(た)。
(.NETのUIだけPython側で欲しい時とかは使えないかな?).NETのソフトからPythonでロジックを実行してC#側にデータを戻す場合
分かりやすい事例だと、事務用のデスクトップアプリなどを作る時、Pythonで書くとUIをPyQtやKivyなどで実装する必要があるが、これらは保守性が低いので、C#などでUIを書いてPythonをコールするイメージ。
今回書くのは1のケースのみです。 2のケースをやらないのは後述します。
.NET向けDLLをPythonで利用する
namespace sample_dll { public class Class1 { int mCounter = 0; public Class1() { mCounter = 0; } public int count() { mCounter += 1; return mCounter; } public void reset_count() { mCounter = 0; } public int out_count(out int c) { c = mCounter; return 0; } public string class_input(Class2 c2) { return c2.message; } } public class Class2 { public string message; public Class2() { message = "this is class2."; } } }
import clr clr.AddReference('sample_dll') from sample_dll import Class1 from sample_dll import Class2 C1 = Class1() c = C1.count() print(c) c = C1.count() print(c) c = C1.count() print(c) d = 0 a = C1.out_count(d) print("a: " + str(a)) print("d: " + str(d)) c2 = Class2() b = C1.class_input(c2) print("b: " + str(b)) print("c2: " + str(c2))
c:\sample\pythonfornet>python main.py 1 2 3 a: (0, 3) d: 0 b: this is class2. c2: sample_dll.Class2
気になったポイント
outパラメータやrefパラメータへの入力の扱いが良く分からなかった。
python側で対応するデータ型にしたダミー変数を準備して放り込む必要がある。
返り値は、関数の返り値にsetのn番目、として返ってくる。
optionパラメータだと更に混乱しそう。。。C#の独自型の入力がよく分からなかった。
上の例くらいだと分からないでもないが、Classの初期化に更に別のClassが必要な場合、書式が煩雑になった。ハマりそうな気がするジェネリック型は意外とサンプル通りで動くので良い。
dllしか持っていない場合でもCodeReflect - Free .NET Decompilerでパラメータを見ながら書けば、割と簡単にそれっぽく動かせる。
感想とか
先にも書いたとおり私が必要としたのは1のパターンです。
他社から購入しているプロプラなソフトとの通信を専用のDLLで実装する必要があったものの、C#とかで書くのが面白くないので使い方を調べました。
対して、世間的には2のケースに対する要求の方が多い気がします。
分かりやすい利用ケースとしては、C#で作ったアプリUIから、PythonのNumpyやPandasやscikit-learnなどの高度演算を利用したい場合などが思いつきました。
でも、後者のケースでは、多くの場合は私は利用しないです。
裏側でPythonでサーバを立てて、表面のC#とRESTなどで通信するとか、単にバッチとしてpython側を実装してファイルで通信するとかの方がコードの分離度が高くて保守性が上がるから。.NET (C#)からpythonを呼び出す - Qiitaにも方法論としての記述はあります。
サーバのプロセスが残ることを良しとしない場合や、C#のUI上で思考錯誤しながら、Pythonとハンドシェイクしながら動かす場合などが対象範囲になるだろうか?
Python側の呼び出し単位が小さくて、APIの開発ややバッチの呼び出しコストが高くなる場合が該当するとは思う。