DevOps

java + python 연결 [ jython ] Accessing Jython from Java Without Using jythonc

IT오이시이 2009. 11. 12. 23:35
728x90

java + python 연결 [ jython ] http://blogimgs.naver.com/imgs/nblog/spc.gif Java   2009/05/26 15:56

복사 http://blog.naver.com/tyboss/70047771617 

첨부파일 (1)

 

http://wiki.python.org/jython/JythonMonthly/Articles/September2006/1

 

Accessing Jython from Java Without Using jythonc

Submitted By: Josh Juneau

You may or may not know that it is possible to access Jython code from Java without compiling it using the jythonc utility. This technique is possible using a mixture of Java interfaces and usage of the PythonInterpreter. As a matter of fact, I believe that using this technique correctly is more effective than using jythonc.

To put it simply, to use this technique you must create a "factory" method which uses the PythonInterpreter class to interpret a .py module for use within Java code. Any Java code that uses the Jython code should be coded against an interface which is implemented by the Jython code.

In order to provide a fully functional example, I've created a simple application with hard-coded data. This application shows the potential for using this technique within your Java applications to have the ability for use of dynamic Jython objects.

The application is simply called "jyinterface" and it contains four pieces of code:

  • -Main.java

-JythonFactory.java - Uses the PythonInterpreter to return a Java object

-EmployeeType.java - An interface which will be implemented by a Jython bean -Employee.py - Jython bean representing an employee

We'll start by coding the "EmployeeType.java" interface which is what our Java code will use in order to interact with the Jython object:

package jyinterface.interfaces;

 

public interface EmployeeType {

   

    public String getEmployeeFirst();

    public String getEmployeeLast();

    public String getEmployeeId();

   

}

The Jython bean "Employee.py" is just a simple Jython object which implements the Java interface "EmployeeType.java":

# Jython source file

from jyinterface.interfaces import EmployeeType

 

class Employee(EmployeeType):

   def __init__(self):

      self.first = "Josh"

      self.last  = "Juneau"

      self.id = "myempid"

 

   def getEmployeeFirst(self):

      return self.first

 

   def getEmployeeLast(self):

      return self.last

 

   def getEmployeeId(self):

      return self.id

Next, the most powerful code for this technique is the "JythonFactory.java" class. This code defines a method which interprets a Jython module into Java and returns for use within Java code. The best part about creating a factory class such as this one is reuse! The factory can be coded in many different ways, but this way allows for reuse because you can essentially pass any Java interface/Jython module to it.

package jyinterface.factory;

 

import org.python.util.PythonInterpreter;

 

public class JythonFactory {

   private static JythonFactory instance = null;

   

   public static JythonFactory getInstance(){

        if(instance == null){

            instance = new JythonFactory();

        }

       

        return instance;

             

    }

   

   public static Object getJythonObject(String interfaceName,

                                        String pathToJythonModule){

             

       Object javaInt = null;

       PythonInterpreter interpreter = new PythonInterpreter();

       interpreter.execfile(pathToJythonModule);

       String tempName = pathToJythonModule.substring(pathToJythonModule.lastIndexOf("/")+1);

       tempName = tempName.substring(0, tempName.indexOf("."));

       System.out.println(tempName);

       String instanceName = tempName.toLowerCase();

       String javaClassName = tempName.substring(0,1).toUpperCase() +

                           tempName.substring(1);

       String objectDef = "=" + javaClassName + "()";

       interpreter.exec(instanceName + objectDef);

        try {

           Class JavaInterface = Class.forName(interfaceName);

           javaInt =

                interpreter.get(instanceName).__tojava__(JavaInterface);

        } catch (ClassNotFoundException ex) {

            ex.printStackTrace();  // Add logging here

        }

 

       return javaInt;

   }

}

As we stated previously, a Java interface/Jython module combo needs to be passed to the getJythonObject method in order to return the resulting code. In the following piece of code, you can see how this is done. Simply pass in two strings:

  1. Fully qualified name of the Java Interface
  2. Full path to the Jython code module

Here is the "Main.java" code:

package jyinterface;

 

import jyinterface.interfaces.EmployeeType;

import jyinterface.factory.JythonFactory;

import org.python.util.PythonInterpreter;

 

 

public class Main {

   

    EmployeeType et;

   

    /** Creates a new instance of Main */

    public Main() {

    }

   

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) {

        JythonFactory jf = JythonFactory.getInstance();

        EmployeeType eType = (EmployeeType) jf.getJythonObject(

                               "jyinterface.interfaces.EmployeeType", "<<path to module>>/Employee.py");

        System.out.println("Employee Name: " + eType.getEmployeeFirst() + " " +

                    eType.getEmployeeLast());

        System.out.println("Employee ID: " + eType.getEmployeeId());

       

    }

}

 

This technique is powerful because it allows an application to use code which can be interchanged or dynamically updated without re-deployment or re-compile. It also follows a great Java practice which is code against Java interfaces!! One downfall to this approach is that the code is interpreted every time it is invoked, so the performance may not be as good as using a jythonc compiled piece of code. It obviously depends upon the requirements of the application, but the usefulness of this technique may outweigh the performance factor in many cases.

Next time you plan to create a Java application that contains some Jython code, give this technique a try

  

=====================================================================

About Python 6
-- Jython
장혜식 (연세대학교 기계전자공학부perky@python.or.kr)
Jython? Jython!
Jython!
기괴한 이름의 언어(?) JPython 계승한, 일반적으로 Python이라 불리는 CPython 다른 자바를 이용한 구현이다. JPython 원래 CPython 별도로 개발되며 CNRI[: 귀도가 95년부터 2000년까지 근무했던 곳으로, Python 1.4부터 1.6까지의 저작권을 가지고 있다.] 저작권으로 만들어진 것이다. 그런데, 지난 2000 10,CPython과의 호환성이나 개발의 일관성을 유지하기 위해서 오픈 프로젝트로 이어받아 JPython 아닌 Jython이라는 이름으로 스포지 (http://jython.sourceforge.net) 기반으로 개발이 진행되고 있다.

CPython 현재 2.1까지 발표되어 있지만, Jython 2.1alpha까지만 발표된 상황이지만, CPython 2.0 Jython 2.0 무난한 호환성을 보여준 것을 보면
으로도 기대할 것으로 보인다.
Jython
C 아닌 자바로 구현되었기 때문에 아직 CPython에서의 모든 기능(대부분 OS 의존적인 모듈들이다)
구현되지 않았고, 언어의 구조에서 정해지지 않은 부동소수점 변수의 문자열 변환이라던지, is 연산자의 행동, 소수점 자르기 등등 세세한 일부에서 차이가 난다.

또한 자바는 모든 문자열이 유니코드 UCS 코드로 되는 이유로 Jython에서도 유니코드 문자열만 허용되지만, CPython에서는 아직 유니코드와 비유니코드를 모두 지원하고 있다.

 이외에도 자바와 C 차이로 인해 세세한 차이가 많이 존재하기는 하지만, 그렇게 불편할 정도는 아니고 오히려try/except에서의 continue 지원이라던지 아직은 불완전한 CPython gc(garbage collector) 비해서, 보다 완벽한 gc 동작 진보된 기능들도 많이 존재한다. 또한, 자바에서는 자체 프레임 스택이 무한대이므로, Stackless Python 누누히 강조하는 무한의 재귀 호출이 Jython에서는 기본적으로 가능하다.

Jython에서 구현이 어려울 것이라 생각되는 os모듈의 popen(), system(), chmod() 등등 Unix 풍의 모듈 함수들은 Finn Bock JNI for posix 의해 어느 정도 극복이 가능하다.


Why Jython?
그렇다면, 과연 자바로 구현되면 과연 어떤 장점이 있기에 C 비해서 느릴 수밖에 없는 자바로 구현이 것일
. 우선, 자바하면 처음 떠오르는 것은 플랫폼에 비의존적이라는 것이다. 결국, 자바 위에서는 Jython 항상 동작
하므로, 자바가 지원하는 플랫폼의 개수보다는 파이썬이 지원하는 플랫폼의 개수는 자바보다 항상 많거나 같다는 재미있는 논리적 결과가 나온다.

그리고, 자바를 하나의 언어로 보기보다는 가상 머신 위의 새로운 플랫폼으로 봐야 한다는 견해를 따르자면, C 많이 쓰이고 있는 일반 환경에서 빠르고 효율적인 개발을 위해 CPython 사용하는 것은 , 자바 언어가 사용되는 자바 플랫폼에서는 Jython으로 빠르고 효율적인 개발이 이루어질 있다는 것과 같은 형식이라고 있다. 실제로, Thinking in Java 저자로서 초기 자바의 전도사로 많은 활동을 했던 Bruce Eckel [: 사실 분은 자바와 파이썬을 같이 얘기할 결코 빠지지 않는 분으로 또다시 인용한 다는 것이 미안할 정도이다] 9 파이썬 컨퍼런스에서의 발표에서 파이썬은 보통 C 비해 10, 자바에 5 정도의 개발속도를 가지게 되므로 자바 플랫폼에서는 앞으로 당연히 Jython 사용되어야 한다는 말을 했다.

이쯤되면, 신기한 것을 좋아하는 일반적인 프로그래머들이라면 번쯤은 맛보아야 직성이 풀릴 것인데, 자세한 것보다는 Jython 재미있는 가지 단적인 부분을 알아봄으로써 Jython 중독된 독자를 늘이는 것을 목적으로 간단한 맛보기를 보도록 하겠다.


Jython
설치하기
사실 설치는 About에서 다루기는 부적합한 소재이긴 하지만, 아직 국내에 Jython 참고자료가 전혀 없기 때문에
간략히 짚어 보도록 하겠다. 우선, Jython 동작하기 위해서는 자바 1.1이나 1.2호환의 VM 필요하다. Unix 환경에
서는 Blackdown, IBMJava, SunJavaSDK 등의 것을 설치해야 하고, MS-Windows 환경에서는 IE 4.0이상이 설치되어
경우에는 일반적으로 JView라는 간단한 자바 가상머신이 설치되어 있다. 우선, 설치하기 위해서 Jython사이트
(http://www.jython.org/download.html)
에서 설치파일을 다운로드 받도록 하자. Jython 인스톨러는 class파일 하나로 이루
어져 있는데, GUI 가능한 환경이라면 직접 class 파일을 실행하면 되고, 콘솔에서 설치하는 경우에는 다음과 같이
설치하면 된다.
# java jython-20 -o Jython-2.0 demo lib source
미리 CLASSPATH 현재 디렉토리(.) 포함되어 있어야 하는데, 포함되어 있지 않은 경우에는 자기가 사용하는
VM
맞게 CLASSPATH . 추가해 후에 실행한다. 자세한 설치 정보는 Jython 홈페이지를 참고하도록 한다.


Jython
에게 인사하기
설치가 되었으면 PATH 환경변수를 적당히 수정해서 쉽게 실행할 있도록 다음에 자바식으로(?) 인사를 보도록 하자.
$ jython
Jython 2.0 on java1.3.0 (JIT: jitc)
>>> from java.lang import System
>>> System.out.println("Hello Jython World!")
Hello Jython World!
자바에서 기본적으로 전역 네임스페이스에 들어가 있는 것들이 파이썬의 기본 키워드들과 충돌하는 것이 많으므로 위와 같이 java.lang에서 import해오는 형식으로 사용해야 한다. 그리고, 파이썬의 기본 키워드 중에 자바의 네임스페이스와 중복되는 것이 있으면 print_ 같은 형식으로 사용한다. 파이썬과 자바는 데이터타입이 서로 다르기때문에 파이썬의 타입은 다음과 같이 변환된다.

Jython 애플리케이션 컴파일하기
Jython으로 만들어진 소스는 CPython에서의 freeze 비슷한 방법으로 Jython 설치되지 않은 상황에서 실행될
있도록 컴파일될 있다. Jython 파이썬 소스를 우선 자바 소스파일로 컴파일한 후에 소스 파일을 외부의
컴파일러를 호출하여 컴파일하는 것이기 때문에, 별도의 JDK 필요한데, MS jvc로는 제대로 컴파일되지 않으므
가급적이면 IBM Jikes Sun JDK 사용하도록 한다. 리스트1 간단한 예제를 자바 클래스로 컴파일해 보도록
하자.
<
리스트 1 : 간단한 Jython 게임(?)>
from java.util import Random
from java.lang.System.out import println
rseed = Random()
Jython Java
string char
int (0
false, 외는 true) boolean
int byte, short, int, long
float float, double
string java.lang.String, byte[], char[]
[] (
리스트) [] (배열)
파이썬 객체 그대로 전달
1 Jython Java 데이터타입 변환
rans = int(rseed.nextDouble() * 20)
while 1:
ans = int(raw_input("Try >>> "))
if ans < rans:
println("more~!")
elif ans > rans:
println("less.. :)")
else:
println("Yes! You got it!")
break
리스트1 JDK1.1 이상에서 지원되는 java.util.Random 이용해서 난수를 발생해서 숫자를 맞추는 게임이다. (
, 지난 5월호에도 나왔던 내용이다.) 물론, Jython에도 System.out.println()대신 print 키워드를 이용할 수도 있다.
소스를 컴파일하려면 레지스트리 파일에서 자바 컴파일러를 지정한 뒤에[: Jython 레지스트리는 Unix에서는
디렉토리의 .jython파일에, MS-Windows에서는 Jython 설치한 곳의 registry파일을 수정하여 사용한다.] Jython 포함
되어 있는 jythonc 이용해서 컴파일한다.

$ /usr/local/jython/jythonc --core --deep --jar JyGame.jar JyGame.py
processing JyGame
Required packages:
java.lang
java.util
...
중략...
Building archive: JyGame.jar
$ /usr/local/jdk/java -cp JyGame.jar JyGame
Try >>


Jython
으로 컴파일된 클래스파일은 jython.jar 필요하게 되는데, jythonc에서 --core옵션을 주면 jython.jar에서 사용
하는 클래스파일들만 뽑아서 다시 jar파일로 만들어 준다. 따라서, class파일로 컴파일한 경우에는 jython.jar 클래스
패스에 넣어주어야 하고 jar 만든 경우에는 파일을 클래스패스에 넣어주면 된다.
Jython
애플릿 만들기
자바는 아무래도 환경에 많은 비중이 있는 만큼, Jython 애플릿으로 많은 것들이 제작되고 있다. 자바 애플
릿으로 만들기 위해서는 자바의 java.applet 클래스를 상속해야 하는데, Jython에서는 파이썬 클래스 아니라 자바
클래스의 서브클래싱도 지원하므로, 아주 간단하게 만들 있다. 하나 주의할 점은 여러 가지 문제로 인해 브라우
저의 JVM 버전과 컴파일시에 사용한 JVM 버전이 다르면 애플릿이 제대로 실행되지 않는 경우가 많으므로 가급적
이면 같은 버전을 사용해야 한다.

<리스트2, Jython 애플릿: 간단한 드로잉 애플릿>
from java import applet, awt
from pawt import GridBag
class JpyLine(applet.Applet):
    def init(self):
    bag = GridBag(self)
    panel = awt.Panel()
    panel.setLayout(awt.GridLayout(1,0))
    panel.background = awt.Color.white
    panel.add(JpyCanvas())
    bag.addRow(panel, weightx=1.0, weighty=1.0, fill='BOTH')

class JpyCanvas(awt.Canvas):
    def __init__(self):
    awt.Canvas.__init__(self)
    self.mousePressed = self.push
    self.points = []
    def push(self, e):
    self.points.append([e.x, e.y])
    self.repaint()

def paint(self, g):
    lp = None
    for p in self.points:
        if lp:
            g.drawLine(lp[0], lp[1], p[0], p[1])
            lp = p


<
리스트2> awt 이용한 그리기만 지원하는 간단한 애플릿이다. java.applet Applet클래스를 서브클래싱하
init() 메쏘드에서 초기화하면서 패널과 캔버스를 추가하도록 하였다. 캔버스의 mousePressed 이벤트 핸들러에
push
등록하여 paint에서 선을 그릴 있도록 리스트에 넣어주었다. 이렇게 Jython에서는 파이썬과 완전히 동일
인터페이스로 간편하게 자바 애플릿을 만들 있다.
자바 안에서 파이썬 사용하기
지금까지는 계속 Jython에서 자바 클래스를 불러오는 것을 했는데, 반대도 역시 가능하다. CPython에서도 C-Python Embedding 가능한 것과 거의 같은 형식으로 가능한데, Jython에서는 쉽게 있다.

<리스트3>JDK에는 기본으로는 들어있지 않은 파이썬 정규표현식 라이브러리를 자바에서 사용하는 예이다.[: 아파치-자카르타 프로젝트의 부산물로 순수 자바로 구현된 정규표현식 클래스도 존재한다.]

[리스트3: 자바에서 파이썬의 re모듈을 이용하는 예제]
import org.python.util.PythonInterpreter;
import org.python.core.*;
public class JPyRegex
{
    public static void main(String []args)
    {
        String todel="Hello <u><b>J</b>ython</u>";
        System.out.println("Before / " + todel);
        System.out.println("After / " + deltag(todel));
    }

public static PyObject deltag(String todel)
throws PyException
{
    PythonInterpreter interp = new PythonInterpreter();
    interp.exec("import re");
    interp.exec("delre = re.compile('<[^>]*>')");
    interp.set("todel", new PyString(todel));
    interp.exec("result = delre.sub('', todel)");
    return interp.get("result");
}

}



CPython
에서 C소스 안으로의 파이썬 소스 엠베딩과 같은 방법으로 우선 인터프리터를 생성한다. 그리고,
터프리터로 파이썬 코드를 보내서 실행한다. 파이썬의 모든 변수형, 클래스등을 포함한 객체들은 PyObject 다뤄지
, 사이의 변환은 PyTuple, PyString, PyInteger 등의 함수로 파이썬에 전달하고, 인터프리터의 get 메쏘드를 이용
해서 PyObject 변환하여 자바측으로 얻어올 있다. 외에 파이썬 객체들을 직접 자바에서 이용하려는 시도가
있었지만 아직은 여러 가지 문제로 인해 일부만 지원되므로 아직은 CPython 같은 방법으로 인터프리터 인스턴스
통한 인터페이스만이 지원되고 있다.
파이썬으로 자바를 잡기
흔히 자바를 잡아라 라는 말이 자바 입문서에 많이 등장한다. 하지만, 주위에서 쉽게 발견할 있었듯이 자바
잡는 사람보다 자바에게 잡히는 사람이 상당수 있었다. 하지만, 자바 이제 가장 대표적인 아키텍처에 비의존
적인 플랫폼으로 자리 잡았으므로, 그를 따라가지 않기는 힘든 상황이다. 어차피 네이티브 코드에 비해서 느린
바에서 파이썬의 실행 속도는 거의 문제되지 않는다. 최근 귀도가 공식적으로 강한 Jython 지원을 시작한 이상
이썬의 뛰어난 개발 효율성, 자바의 뛰어난 이식성과 다양한 지원, 그리고 CPython과의 호환성을 토대로해 자바
랫폼에서도 Python 열풍이 닥칠지도 모른다. 아직 Jython 인터프리터와 포팅에 필요한 자바 프로그래머의
부족으로 개발 속도가 더딘 편이다. 뜻이 있는 자바 프로그래머들의 많은 지원을 기대한다.

 

[출처] java + python 연결 [ jython ]|작성자 마루아라


728x90
반응형