JavaでPythonプログラミング

JavaでPythonプログラミング



大阪Pythonの会 #18 2018/10

Who am I

icon ergodox

名前:
ごうじん
所属:フリーランス
Python歴:5年
お気に入り:Tornado, Click
活動:tornado-crontab

質問

質問


仕事でJavaを使っている

こんなこと思ったことありません?

これ、Pythonだったら一瞬なのに...

JavaでPythonが動けばいいのに...

それ、

Jythonで実現できますよ

Outline


  • Jythonとは `                 `

  • CPythonとの違い `              `

  • Jythonの使い方 `               `

  • Jythonの使い所 `               `

  • Jythonの可能性とこれから `          `

  • まとめ `                   `

Jythonとは

Jythonとは


  • Jython(旧称JPython)は、JVM(Java仮想マシン)で動作するPython実装。Jim Huguninによって開発が始められ、今はJythonコミュニティに引き継がれている

  • Pythonから、Javaのクラスやライブラリをインポートして使うことができたり、その逆もできる

  • 一部の標準モジュールを除いて、Javaのクラスを使用しているので、CPythonとは異なる挙動をすることがある

ライセンス: Python Software Foundation License Version 2
最新バージョン: 2.7.1(2017-06)

CPythonとの違い

CPythonとの違い


  1. C言語拡張はできない

    CPythonの拡張モジュールの大部分は動作するが、C言語で拡張された、もしくは、Cライブラリを参照しているモジュールは動作しない。

    JyNI(Jython Native Interface)経由でC拡張されたモジュールなら動くかもしれない。




CPythonとの違い


  1. バイトエンコーディングファイルがちがう

    CPythonは通常、バイトコンパイルした場合、.pyc(または.pyo)ファイルを生成するが、Jythonは、$py.classファイルを生成する。

    JVM上で動作するので当然だが、CPython・Jython間でバイトエンコーディングファイルは共有できない。








CPythonとの違い


  1. GIL(Global Interpreter Lock)と戦う必要はない

    CPythonでは、mutiprocessingを使ってGILを回避するが、Jythonは、Javaのスレッドを利用するので、GILは起こらない。

    Jythonにmultiprocessingモジュールは移植されていないので、multiprocessingで実装したソースコードは動作しない。



Jythonの使い方

Jythonのインストール

次の3つから、インストール方法を選べる

  • GUIインストール

  • コンソールインストール

  • ライブラリとして使う(スタンドアローン)

GUIインストール

GUIインストール

www.jython.org http://www.jython.org/downloads.html

GUIインストール

$ curl -OL https://repo1.maven.org/maven2/org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar
$ java -jar jython-installer-2.7.1.jar











GUIインストール

install_jython_1

コンソールインストール

コンソールインストール

$ curl -OL https://repo1.maven.org/maven2/org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar
$ java -jar jython-installer-2.7.1.jar \
       --console \
       --silent \
       --type standard \
       --directory /path/to/jython








コンソールインストール

$ curl -OL https://repo1.maven.org/maven2/org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar
$ java -jar jython-installer-2.7.1.jar \
       --console \
       --silent \
       --type standard \
       --directory /path/to/jython

Performing silent installation
 10 %
 20 %
 30 %
 40 %
 50 %
 60 %
 70 %
 80 %
Generating start scripts ...
Installing pip and setuptools
 90 %
Collecting setuptools
Collecting pip
Installing collected packages: setuptools, pip
Successfully installed pip-9.0.1 setuptools-28.8.0
 100 %
Congratulations! You successfully installed Jython 2.7.1 to directory /path/to/jython.

ライブラリとして使う

(スタンドアローン)
$ java -jar jython-installer-2.7.1.jar \
       --console \
       --silent \
       --type standalone \
       --directory /path/to/jython

OR

$ curl -OL https://repo1.maven.org/maven2/org/python/jython-standalone/2.7.1/jython-standalone-2.7.1.jar






Jythonを実行する

Jythonを実行する

# GUI及びコンソールインストールした場合

$ /path/to/jython/bin/jython [Pythonコードファイル]

# ライブラリとして使う場合

$ java -jar jython-standalone-2.7.1.jar [Pythonコードファイル]

# 対話モード

$ /path/to/jython/bin/jython






Jythonを実行する

※Java9以降を使った場合は、警告が出るが問題なく動く

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by jnr.posix.JavaLibCHelper (file:/path/to/jython/jython.jar) to method sun.nio.ch.SelChImpl.getFD()
WARNING: Please consider reporting this to the maintainers of jnr.posix.JavaLibCHelper
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release








JythonでPythonコードを実行する

JythonでPythonコードを実行する

jp/gaujin/py/Simple.py
# coding: utf-8
import random

VALUES = ['spam', 'ham', 'egg']

def choice():
    return random.choice(VALUES)

if __name__ == '__main__':
    print choice()
$ /path/to/jython/bin/jython jp.gaujin.py.Simple
spam

Javaモジュールをロードする

Javaモジュールをロードする

jp/gaujin/java/Simple.java
package jp.gaujin.java;
import java.util.Random;

public class Simple {

    public static final String[] VALUES = { "foo", "bar", "baz" };
    private static Random random = new Random();

    public static String choice() {
        return VALUES[random.nextInt(VALUES.length)];
    }
}
Embedded3.py
from jp.gaujin.java.Simple import choice

if __name__ == '__main__':
    print choice()

Javaコード内にPythonコードを書く

Javaコード内にPythonコードを書く

Embedded1.java
import org.python.util.PythonInterpreter;

public class Embedded1 {

    public static void main(String... args) throws Exception {
        PythonInterpreter pi = new PythonInterpreter();
        pi.exec(String.join(System.getProperty("line.separator")

            , "# coding: utf-8"
            , "import random"

            , "VALUES = ['spam', 'ham', 'egg']"

            , "def choice():"
            , "    return random.choice(VALUES)"

            , "if __name__ == '__main__':"
            , "    print choice()"

        ));
    }
}

Javaコード内にPythonコードを書く

Embedded1.java
import org.python.util.PythonInterpreter;

public class Embedded1 {

    public static void main(String... args) throws Exception {
        PythonInterpreter pi = new PythonInterpreter();
        pi.exec(String.join(System.getProperty("line.separator")

            , "# coding: utf-8"
            , "import random"

            , "VALUES = ['spam', 'ham', 'egg']"

            , "def choice():"
            , "    return random.choice(VALUES)"

            , "if __name__ == '__main__':"
            , "    print choice()"

        ));
    }
}

Pythonモジュールをロードする

Pythonモジュールをロードする

jp/gaujin/py/Simple.py
# coding: utf-8
import random

VALUES = ['spam', 'ham', 'egg']

def choice():
    return random.choice(VALUES)

if __name__ == '__main__':
    print choice()

Pythonモジュールをロードする

Embedded2.java
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;

public class Embedded2 {

    public static void main(String... args) throws Exception {
        PythonInterpreter pi = new PythonInterpreter();
        pi.exec(

            "from jp.gaujin.py.Simple import choice"

        );

        PyObject choice = pi.get("choice");
        PyObject value = choice.__call__();

        System.out.println("value: " + value);
    }
}

Pythonモジュールをロードする

Embedded2.java
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;

public class Embedded2 {

    public static void main(String... args) throws Exception {
        PythonInterpreter pi = new PythonInterpreter();
        pi.exec(

            "from jp.gaujin.py.Simple import choice"

        );

        PyObject choice = pi.get("choice");
        PyObject value = choice.__call__();

        System.out.println("value: " + value);
    }
}

Pythonモジュールをロードする

Embedded2.java
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;

public class Embedded2 {

    public static void main(String... args) throws Exception {
        PythonInterpreter pi = new PythonInterpreter();
        pi.exec(

            "from jp.gaujin.py.Simple import choice"

        );

        PyObject choice = pi.get("choice");
        PyObject value = choice.__call__();

        System.out.println("value: " + value);
    }
}

Jythonの使い所

提案(1)


Java製システムをJythonで拡張する

suggest1

提案(2)


既存サービスから新サービスへのデータ移行

suggest2

提案(3)


Pythonへの開発言語移行推進

java arrow jython arrow python

Jythonの可能性とこれから

Jythonの可能性

可能性(1)

軽量Webフレームワークを使う
$ /path/to/jython/bin/pip install bottle flask

可能性(2)

Djangoを使う
$ /path/to/jython/bin/pip install django
Collecting django
  Using cached https://files.pythonhosted.org/packages/44/e7/872bbf76aa16b7a061698d75325dac023285db33db4bda8ba8fe5d3bb356/Django-1.11.16-py2.py3-none-any.whl
Collecting pytz (from django)
  Using cached https://files.pythonhosted.org/packages/f8/0e/2365ddc010afb3d79147f1dd544e5ee24bf4ece58ab99b16fbb465ce6dc0/pytz-2018.7-py2.py3-none-any.whl
Installing collected packages: pytz, django
Successfully installed django-1.11.16 pytz-2018.7
インストールは成功しているように見えるが、実行してみると、sqlite3のエラーになる

可能性(2)

Djangoを使う
$ /path/to/jython/bin/pip install django-jython
Collecting django-jython
  Downloading https://files.pythonhosted.org/packages/7d/e8/f6ec1f54a8364e04d6d27584dec1b74cdf3af62f84651c42ff6b874cbe21/django-jython-1.3.0.tar.gz (175kB)
    100% |████████████████████████████████| 184kB 538kB/s
Installing collected packages: django-jython
  Running setup.py install for django-jython ... done
Successfully installed django-jython-1.3.0
とても古いDjangoがインストールされます

可能性(2)

Djangoを使う
$ git clone https://github.com/beachmachine/django-jython.git
$ cd django-jython
$ python install setup.py
running install
running bdist_egg
running egg_info
writing dependency_links to django_jython.egg-info/dependency_links.txt
writing top-level names to django_jython.egg-info/top_level.txt
writing django_jython.egg-info/PKG-INFO

                                                       :

Installed /path/to/jython/Lib/site-packages/Django-1.8.19-py2.7.egg
Finished processing dependencies for django-jython==1.8.0b4
django-jythonのGithubリポジトリからチェックアウトし、インストールすることで、対応しているDjangoをインストールできる

可能性(2)

Djangoを使う

django_admin_login

可能性(2)

Djangoを使う

django_admin

可能性(2)

Djangoを使う

django_admin_error

可能性(3)

JyNIを使う

jyni.org http://www.jyni.org

可能性(3)

JyNIを使う

jyni.org.compati

Jythonのこれから

Jythonのこれから

Python3のサポート

jython3_sandbox https://github.com/jython/jython3/

まとめ

まとめ

Jythonとは

  • Jythonは、JVMで動作するPython実装
  • PythonとJavaで、クラス、ライブラリを相互インポートできる






まとめ

CPythonとの違い

  • C言語拡張はできない

  • バイトエンコーディングファイルがちがう

  • GILと戦う必要はない
          :



まとめ

Jythonの使い方

  • Jythonのインストール `             `

    • GUI・コンソール・スタンドアローンの3種類

  • Jythonを実行する

    • JythonでPythonコードを実行
    • Javaコード内のPythonコードを実行
    • Java・Pythonモジュールを相互インポート

まとめ

Jythonの使い所

  • Java製システムをJythonで拡張 `         `
  • 既存サービスから新サービスへのデータ移行
  • Pythonへの開発言語移行推進






まとめ

Jythonの可能性とこれから

  • Jythonの可能性 `                `

    • 軽量Webフレームワーク・Django・JyNIを使う

  • Jythonのこれから

    • Python3のサポートは 3.5 から


ご清聴ありがとうございました

よいJythonライフを!!