[PR]今日のニュースは
「Infoseek モバイル」


Jython APIをJavaアプリケーションから使うには

 Jythonに含まれる「jython.jar」をCLASSPATHに含めておくと、Javaアプリケーションの中から、 Pythonのプログラム・コードを解釈実行することができます。 これはEmbedding(埋め込み)と呼ばれますが、このページでその簡単な例を幾つかご紹介します。
前準備として、環境変数CLASSPATHにjython.jarを含めておきましょう。

% setenv CLASSPATH /usr/local/jython-2.1a3/jython.jar:$CLASSPATH

最も簡単なサンプル
まずは簡単なサンプルです。 何をしているのか、どんな結果が返ってきそうかは、 きっと見ただけでお分かりと思います。

import org.python.util.PythonInterpreter;
import org.python.core.*;

public class JyEmbedTester1 {

    public static void main(String[] args){
        PythonInterpreter interp = new PythonInterpreter();
        PyObject result;

        // PyObjectをセットする例
        interp.set("var1", new PyInteger(100));
        interp.exec("var2 = var1 + 25");
        result = interp.get("var2");

        System.out.println("RESULT=" + result.toString());

        // java.lang.Objectをセットする例
        interp.set("var1", "Hello, ");
        interp.exec("var2 = var1 + \"World.\"");
        result = interp.get("var2");

        System.out.println("RESULT=" + result.toString());
    }
}

プログラムの基本的な要素は上でおおむね押えていると思います。 まず、Pythonインタープリタ を作ります。これは、Java的に言いますと、クラス PythonInterpreterのインスタンスであります。

PythonInterpreter interp = new PythonInterpreter();

PythonインタープリタはJava世界とPython世界のデータの受渡しをする役目をもっていて、 まず setメソッドでPython世界の任意の変数に値をセットします。 これには2つの方法があって、 PyIntegerPyLangなどの、Pythonデータ型を具現化させた Javaクラス(PyObjectクラスのサブクラス) で渡す方法と、java.lang.Object のインスタンス(つまり、普通一般のJavaオブジェクト) で渡す方法があります。

// PyObjectのサブクラスで渡す
interp.set("var1", new PyInteger(100));
// java.lang.Objectのサブクラスで渡す
interp.set("var1", "Hello, ");
Java言語では、boolean、intなどの単純データ型は java.lang.Objectのサブクラスではありませんから、 これらのデータを渡すときには前者の方法を、そうでなければ後者の方法を使います。 後者を使う例のほとんどは、上の例のように文字列をセットする場合です。

次に、実際にPythonコードを実行するには、 execメソッドを使います。 この使い方は簡単です。計算式の文など以外にも、下のように import文なども実行できます。

interp.exec("import sys");
interp.exec("var2 = var1 + 25");

最後に処理結果を取得したくなったら、 getメソッドの出番です。 このメソッドは、引数で指定した名前のPython変数をJava世界に引っ張ってくるはたらきをします。 そのデータは、先程ちょっと出て来た PyObjectのインスタンスです (実際には、後でふれる通り、そのサブクラスのインスタンスであることがほとんどです) 。
PyObject result = interp.get("var2");
System.out.ptintln(result.toString());
このように、toStringメソッドを使うと完全にJava文字列として使うことができます。

さてそれでは、このJavaクラスをコンパイルして実行してみましょう。 このやり方は普通のJavaアプリケーションと同じです。

% javac JyEmbedTester1.java
% java JyEmbedTester1

スクリプトファイルを解釈実行する
Pythonのスクリプトファイルを、Javaコードから解釈実行させて、 その処理の中で作られたPython変数を取得することもできます。

import os, time
from stat import *

def enstat(filename):
  stst = os.stat(filename)
  sz = stst[ST_SIZE]
  mtime = stst[ST_MTIME]
  tm = time.localtime(mtime)
  mtimestr = time.strftime("%Y/%m/%d %H:%M:%S", tm)
  return (filename, sz, mtimestr)

files = os.listdir(".")
resultval = [ ]
for e in files:
  s = enstat(e)
  resultval.append(s)

if __name__ == '__main__':
  print resultval
# end.

上のスクリプトは、カレントディレクトリの全部のファイルについて、 「ファイル名、ファイルサイズ、編集日」の3要素からなるたっぷる(Tuple) を作り、それらのリストにして変数resultvalに格納する処理をします。 つまり、変数resultvalにはたっぷるのリストが格納されていることになります。 それでは、上のスクリプトを「filestat.py」 と名付け、Javaコードから呼び出してみます。 下のようなプログラムを作ってみました。

import org.python.util.PythonInterpreter;
import org.python.core.*;

public class JyEmbedTester2 {

    public static void main(String[] args){
        PythonInterpreter interp = new PythonInterpreter();
        PyList result;
        PyTuple fileinfo;

        interp.execfile("./filestat.py");
        result = (PyList) interp.get("resultval");
        for(int i=0; i<result.__len__(); i++){
            fileinfo = (PyTuple) result.__getitem__(i);
            for(int j=0; j<fileinfo.__len__(); j++){
                PyObject obj = fileinfo.__getitem__(j);
                System.out.print("[" + obj.toString() + "]");
            }
            System.out.println("");
        }
    }
}
// end.

インタープリタの初期化処理は同じですが、 今度はスクリプトファイルを実行するために execfileというメソッドを使っています。 このメソッドで指定したPythonスクリプトファイルが実行できます。 そのスクリプトの変数resultvalの値は先述の通り、 Python世界では「たっぷるのリスト」です。 では、Java世界ではどうなるのでしょう? まず、一次的には、この変数はリストですから、 PyObjectのサブクラスの中の PyListにキャスト(強制型変換)して受け取ることができます。

PyList result = (PyList) interp.get("resultval");
そして、そのリストの各要素は今度はたっぷるですから、 1つずつPyTupleオブジェクトとして取り出します。 その際、リストやたっぷるの要素の数は、 Java世界では__len__ メソッドで知ることができます。 また、各要素を取得するには、__getitem__ メソッドを使います。つまり、ちょっとまだるっこしいですが、 Python世界の
resultval[2]
は、Java世界では、
resultval.__getitem__(2)
となるわけです。最後に、取り出したたっぷるは 「ファイル名、ファイルサイズ、編集日」の3要素からなるので、 それぞれをリストのときと同様に取り出して、toString()で文字列に変換しているだけです。

インタープリタのexec関数と日本語
 次のサンプルのように、PythonInterpreter#exec()メソッドで実行するスクリプトの中に日本語の文字列を使っていると、 文字化けします。 (execfileメソッドで実行するスクリプトの中には日本語を使っても問題ありません) 例えば下のサンプルを実行すると、「ハロー」は正しく表示されますが、 「ワールド」は文字化けしてしまいます。 これを修正するには、Jythonのソースプログラムを1か所変更してビルドします。 詳しくは、こちらにまとめました。

import org.python.util.PythonInterpreter;
import org.python.core.*;

public class EmbedExample {
    public static void main(String[] args){
        PythonInterpreter interp = new PythonInterpreter();
        PyObject result;

        interp.set("var1", "ハロー、");
        interp.exec("var2 = var1 + \"ワールド。\"");
        result = interp.get("var2");

        System.out.println("RESULT=" + result.toString());
    }
}
// end.

セクションのサブメニューに戻る
(first uploaded 2001/09/23 last updated 2004/05/08)