はじめに
機械学習や最適化、数値計算はPythonのライブラリがC#に対して非常に充実しているので、C#で簡単にできないことが多いしラッパーやC#むけに書き換えるのも時間がかかる。
そういった場合に役に立つライブラリ Pythonnet について紹介します。
このライブラリは、C#からPythonの関数を呼び出すことが出来る非常に便利なライブラリで.NET Foundationからもサポートを受けて開発されています。
PythonからC#を呼び出す機能も提供されていてそちらの方が記事が多いですが、C#からPythonを呼び出す記事はあまりなかったので備忘録的に作成しました。
型について
C#の型のままではPythonの関数に値を渡せないので、Python用の方に変換する必要があります。
基本的にはPyHoge型が存在してそれに変換します。
文字列
string str = "Foo";
var pyStr = new PyString(str);
整数型
int intNum = 1;
var pyInt = new PyInt(intNum);
倍精度浮動小数点型
double doubleNum = 4.5;
var pyFloat = new PyFloat(doubleNum);
リスト
// C# のリストではなく Python(動的型付け) のリストなので
// List<T> のTような型指定はない
var strList = new PyList();
// Python のリストなので Add ではなく Append
list.Append(new PyString("foo"));
list.Append(new PyString("bar"));
list.Append(new PyString("baz"));
// 以下のようにも作れる
var pyObj = new PyObject[] {new PyInt(3), new PyInt(2), new PyInt(1) };
var pyList = new PyList(pyObj);
連想配列
var dict = new PyDict();
dict.SetItem("key1", new PyFloat(10.0));
dict.SetItem("key2", new PyFloat(20.0));
拡張メソッド
これまでPyHoge型をnewを使って作成する方法について書いてきたが、よく使う型については拡張メソッドが用意されているので、基本的にはC#そのままで書いていても問題なく変換できる。
//リストの例
var csList = new List<double>{1, 2, 3, 4};
// ToPython()メソッドがPythonに変換してくれる
PyObject py_list = csList.ToPython();
ライブラリのインポート
単純なインポートなら以下のように書ける。
import numpy
↓
dynamic numpy = Py.Import("numpy")
from A import B の場合は以下のようにすればimportはできる。
from math import radians
↓
dynamic radians = Py.Import("math").GetAttr("radians");
もちろん以下のようにも書ける
PyModule ps = Py.CreateScope();
ps.Exec(
"from math import radians"
);
dynamic radians = ps.Get("radians");
公式のサンプル
C# で Numpy を使う例
既存のライブラリは簡単にC#側から呼ぶことが出来る。公式に記載されているC#からNumpyを呼び出す例は以下。
IDEのコードヒントは全くでないのでPython側のライブラリをよく把握していないとC#単体でPythonのコードをタイポなく呼ぶのは難しい。
だいたいの場合は一回Pythonで書いてからC#に書き換える方が楽な場合が多い
static void Main(string[] args)
{
PythonEngine.Initialize();
using (Py.GIL())
{
dynamic np = Py.Import("numpy");
Console.WriteLine(np.cos(np.pi * 2));
dynamic sin = np.sin;
Console.WriteLine(sin(5));
double c = (double)(np.cos(5) + sin(5));
Console.WriteLine(c);
dynamic a = np.array(new List<float> { 1, 2, 3 });
Console.WriteLine(a.dtype);
dynamic b = np.array(new List<float> { 6, 5, 4 }, dtype: np.int32);
Console.WriteLine(b.dtype);
Console.WriteLine(a * b);
Console.ReadKey();
}
}
// Output
// 1.0
// -0.958924274663
// -0.6752620892
// float64
// int32
// [ 6. 10. 12.]
Pythonの関数をC#側で書いてC#側で呼ぶ方法
既存のライブラリを呼ぶまでもないものや、C#で書くと面倒なものは以下のように文字列としてC#上で書くとPythonコードとして使うことが出来る
PythonEngine.Initialize();
using (Py.GIL())
{
PyModule ps = Py.CreateScope();
ps.Exec(
"def add(a, b):\n" +
" return a + b\n" // Python を書いているのでインデントを忘れずに
);
// ここで上記で作成した add メソッドをC#側に取得している
dynamic add = ps.Get("add");
var result = add(1, 2) // result = 3
}