2009-01-13 21 views
10

Tengo un programa de python, que se ejecuta en la implementación de CPython, y dentro de él debo llamar a una función definida en un programa de Java. ¿Cómo puedo hacer esto?Cómo llamar a objetos y funciones Java desde CPython?

Sería bueno poder usar algunos objetos Java también.

Jython no es una opción. Debo ejecutar la parte de python en CPython.

Respuesta

9

La cosa más fácil que hacer es

  1. Escribe un CLI trivial para su Java "función". (No hay tal cosa, así que asumiremos que significa realmente una función método de una clase Java.)

    public class ExposeAMethod { 
        public static void main(String args[]) { 
         TheClassToExpose x = new TheClassToExpose(); 
         x.theFunction(); 
        } 
    } 
    
  2. compilar y generar un archivo JAR ejecutable con esto como el punto de entrada. Llámelo ExposeAMethod.jar

  3. Llamar desde un comando creado por subproceso.

    import subprocess 
    p = subprocess.Popen("java -jar ExposeAMethod.jar", shell=True) 
    sts = os.waitpid(p.pid, 0) 
    

Este es el mínimo. Y realmente no es mucho. Cuento 6 líneas de java, 3 líneas de Python y ya está funcionando.

Si desea pasar argumentos a este constructor de clase Java o función de método, tendrá que escribir algunas líneas más de código. Tienes dos opciones.

  • Lea los argumentos de stdin, escriba los resultados en stdout. Esto es relativamente fácil y funciona muy bien.

  • Analice los argumentos como opciones de línea de comandos en Java, escriba los resultados en stdout. Esto es un poco más difícil, pero se generaliza muy bien. La ventaja es que ahora tiene un útil programa de línea de comandos Java que puede reutilizar.

1

No sé para Python, por última vez tuve que llamar a Java desde la aplicación C (servicio NT) tuve que cargar jvm.dll. Eche un vistazo a la documentación de JNI.

Además, llame siempre a os.system ("java com.myapp.MyClass") si no está preocupado por el rendimiento.

7

Si no quiere ir, escriba su propia ruta JNI/C.

La otra opción es usar jpype, que para mí siempre es lo que uso para acceder a las bases de datos de Oracle, ya que la instalación de los controladores oracle c en una PC es una pita. Usted puede hacer cosas por el estilo (de documentos):

from jpype import * 
startJVM("d:/tools/j2sdk/jre/bin/client/jvm.dll", "-ea") # or path to your jvm 
java.lang.System.out.println("hello world") 
shutdownJVM() 

No ha sido actualizado desde hace tiempo y no hay mucho en el camino de la documentación pero funciona razonablemente bien.

+0

Los enlaces van a una versión obsoleta. Encuentre la correcta aquí: https://pypi.python.org/pypi/JPype1 https://github.com/originell/jpype y los documentos aquí: https://jpype.readthedocs.io/en/latest/ – bastian

13

Disculpas por resucitar el hilo, pero creo que tengo una mejor respuesta :-)

También es posible usar Py4J que tiene dos partes: una biblioteca que se ejecuta en CPython (o cualquier intérprete de Python para el caso) y una biblioteca que se ejecuta en la máquina virtual Java a la que desea llamar.

Hay un ejemplo en la página principal y un montón de documentación, pero en esencia, que acaba de llamar a métodos Java desde el código Python como si fueran métodos Python:

>>> from py4j.java_gateway import JavaGateway 
>>> gateway = JavaGateway()      # connect to the JVM 
>>> java_object = gateway.jvm.mypackage.MyClass() # invoke constructor 
>>> other_object = java_object.doThat() 
>>> other_object.doThis(1,'abc') 
>>> gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method 

La comunicación se realiza a través de sockets en lugar de JNI.

responsabilidad: yo soy el autor de Py4J

+0

¿Cuáles son los beneficios en el uso de sockets? ¿No es más lento que JNI? ¿Tiene estadísticas de rendimiento? – bastian

+1

¡JNI tiene menos sobrecarga de seguro! Sin embargo, los sockets son más portátiles (JNI no siempre es divertido en Windows) y admiten muchos más escenarios (por ejemplo, un intérprete de Python en una máquina diferente de la JVM). – Barthelemy

1

mirada a nuestro proyecto python-javabridge. Es un contenedor de Python alrededor del JNI, muy usado por CellProfiler. Ofrece acceso de bajo nivel al JNI y un acceso de alto nivel basado en la reflexión a objetos Java.

+0

¿Cómo se compara python-javabridge con [jpype] (https://pypi.python.org/pypi/JPype1)? Rendimiento/estabilidad? – bastian