Jythonに組み込み関数を追加する
某blogのコメント欄
に書いてあったので。
まず関数編。
javaで作成した関数をjython側で組み込み関数として使ってみます。
JythonSample.java
import java.net.URL; import org.python.core.PyString; import org.python.util.PythonInterpreter; import test.TestFunction; /** * * @author Yutaka Matsubara (゚∀゚) */ public class JythonSample { /** * * @param args */ public static void main(String[] args) throws Exception { // Pythonファイルを検索する String fqcn = JythonSample.class.getName(); String resourcePath = fqcn.replace('.', '/') + ".class"; URL url = Thread.currentThread().getContextClassLoader().getResource(resourcePath); String s = url.toString(); s = s.substring(6, s.lastIndexOf("/") + 1) + "builtin.py"; PythonInterpreter pyi = new PythonInterpreter(); // 属性を追加 // Python上のObjectとして組み込む pyi.getLocals().__setitem__("test", new PyString("testStringですよー")); // 関数を属性として追加 // 組み込み関数っぽく組み込む pyi.set("testFunc", new TestFunction()); pyi.execfile(s); } }
関数testFunc
package test; import org.python.core.Py; import org.python.core.PyBuiltinFunctionSet; import org.python.core.PyObject; /** * 受け取った値をコンソールに出力する関数です。 * * @author Yutaka Matsubara (゚∀゚) */ public class TestFunction extends PyBuiltinFunctionSet { /** * すんげーてきとー */ public TestFunction() { super("testFunc", 999, 0, 1, false, null); } /** * 引数なしで呼ばれた場合はエラー */ public PyObject __call__() { throw argCountError(0); } /** * 引数の値をtoStringしてコンソール出力します。 * Objectの型はPyObject */ public PyObject __call__(PyObject arg1) { System.out.println("test function called = " + arg1.toString()); //Noneを返す return Py.None; } }
ちょーてきとーです。
呼び出し側のbuiltin.py
# 全属性出力 print dir() #属性 test print type(test) print test #属性testFunction print type(testFunc) testFunc(test) t = (1,2,3,4) testFunc(t) d = dir testFunc(d)
実行結果
['__doc__', '__name__', 'test', 'testFunc'] <type 'str'> testStringですよー <type 'TestFunction'> test function called = testStringですよー test function called = (1, 2, 3, 4) test function called = <java function dir 1> 終了
dir()で調べてみると両方追加されていますね。
typeを調べてみましたがてきとーな値が出ています。
testFunc(test)
一応一発で呼べますね。
もっと荒業するならばIntercepterにevalで先にいろんなことしておく手もありますね。
クラスの生成→関数を別属性に当てるとかすれば上のコード全く同じことできますね。
c = Class() testFunc = c.TestFunc
こんな感じ。
組み込み関数を作ってみたが多分やり方的には何パターンかありそう。
このサンプルだと関数自体がクラスなので関数内にjavaクラスの参照も持てたりするので自由度が高いと思います。
あとビルトインオブジェクトか。
ビルトインオブジェクトに関してはあんましいらない気がする。
importを減らせるぐらいじゃないかなー?
上記の関数をコンストラクタとして扱いFactory的に使ってオブジェクトを返せばもっと自由度あがると思うし。
うくく。
追記
あ。勘違いかも。
組み込みオブジェクトが何を指しているかが微妙。
組み込み型を指しているのかな?
やりたいことってPyObjectの拡張かしら。
うーん。