これの続き。
これと同じノリで、C# コードを書く、ビルドする、実行する、を全部一個のスクリプトでまかなっちゃう、面倒なので。
で、「寸止め」版:
1 # -*- coding: utf-8 -*-
2 # ---------------------------------------------------
3 from __future__ import absolute_import
4 from __future__ import unicode_literals
5 from __future__ import print_function
6
7
8 if __name__ == '__main__':
9 # ファイルがバラけてると実験が鬱陶しいので C# コードをここに書いてしまって
10 # ビルドも全部やってしまう。
11 import subprocess, os, io, sys
12
13 # C# コード
14 # 公式サイト説明に欠けてるのは:
15 # using Python.Runtime;
16 # PythonEngine.Initialize(); がいるのかいらないのか、入ってなくても
17 # 動いた。CPython の C API のノリなら必要なのだが?
18 #
19 io.open("PyFromCSExam.cs", "w").write("""
20 using System; // for Console, etc.
21 using System.Collections.Generic; // for List
22 using Python.Runtime;
23
24 namespace PyFromCSExam
25 {
26 public class Exam
27 {
28 static void Main(string[] args)
29 {
30 using (Py.GIL())
31 {
32 dynamic np = Py.Import("numpy");
33 Console.WriteLine(np.cos(np.pi * 2));
34
35 dynamic sin = np.sin;
36 Console.WriteLine(sin(5));
37
38 double c = np.cos(5) + sin(5);
39 Console.WriteLine(c);
40
41 dynamic a = np.array(new List<float> { 1, 2, 3 });
42 Console.WriteLine(a.dtype);
43
44 dynamic b = np.array(new List<float> { 6, 5, 4 }, dtype: np.int32);
45 Console.WriteLine(b.dtype);
46
47 Console.WriteLine(a * b);
48 Console.ReadKey();
49 }
50 }
51 }
52 }
53 """)
54 # ビルド
55
56 # site-packages にある Python.Runtime.dll
57 import site
58 cands = site.getsitepackages()
59 for canddir in cands[1:]:
60 pythonengine_dll = os.path.join(canddir, "Python.Runtime.dll")
61 if os.path.exists(pythonengine_dll):
62 break
63 import shutil
64 shutil.copyfile(pythonengine_dll, os.path.basename(pythonengine_dll))
65 subprocess.check_call(
66 [
67 # csc がない、と言われる場合で「ほんとうは持ってる」場合は、
68 # BuildTools 2007 なら、スタートメニューから「x64_x86 Cross Tools
69 # Command Prompt for VS 2017」(等)を探して起動し、その環境から。
70 "csc.exe",
71 "-nologo",
72 "-target:exe", # as console app
73 "-out:PyFromCSExam.exe",
74 "-reference:" + os.path.basename(pythonengine_dll),
75 #"-reference:" + pythonengine_dll,
76 #"-lib:" + pythonengine_dll,
77 "PyFromCSExam.cs",
78 ]
79 )
80 # 実行しちゃいなよ
81 subprocess.check_call(
82 [
83 "PyFromCSExam.exe",
84 ])
「寸止め」つーか「ダメ」ポイントが3つ:
Python.Runtime.dll
をカレントディレクトリにコピーする以外の手段が見つかってない。
(Python.Runtime.dll
自身が別のものに依存しているからっぽいがよくわからん。)- ワタシの環境では Python 2.7 の
python27.dll
がグローバルに可視(「パスが通ってる」)ので 2.7 では動くが、Python 3.5 環境の方がそうなってないので、python35.dll
が見つからない、となって動かない。 - 「動く」ほうの 2.7 も、4つ目の
Console.WriteLine
のあとに落っこちる。
この3つのうち、1. と 2. はプロジェクトによっては問題じゃなかったりする。つまり「エンドユーザが Python をインストールしてようがしてまいが」という何か .NET アプリケーションを開発して「配る」なり「売る」んであれば、自分のインストールフォルダにこれら依存物は一緒に放り込むであろうから。でも多分措置出来ると思うので、頑張ってはみる。
最後のは清く正しく .NET 例外が説明してくれてる(元となったのは python 側の例外らしい(「TypeError : long() argument must be a string or a number
」))。公式のサンプルはどうやら型の扱いを間違っているみたい。すぐに措置出来ると信じているが、保障は出来ない。まぁ頑張ってみる。
続く。