Chiamare Java da Python


123

Qual è il modo migliore per chiamare java da Python? (jython e RPC non sono un'opzione per me).

Ho sentito parlare di JCC: http://pypi.python.org/pypi/JCC/1.9 un generatore di codice C ++ per chiamare Java da C ++ / Python Ma questo richiede la compilazione di ogni possibile chiamata; Preferirei un'altra soluzione.

Ho sentito parlare di JPype: http://jpype.sourceforge.net/ tutorial: http://www.slideshare.net/onyame/mixing-python-and-java

import jpype 
jpype.startJVM(path to jvm.dll, "-ea") 
javaPackage = jpype.JPackage("JavaPackageName") 
javaClass = javaPackage.JavaClassName 
javaObject = javaClass() 
javaObject.JavaMethodName() 
jpype.shutdownJVM() 

Questo sembra quello che mi serve. Tuttavia, l'ultima versione è del gennaio 2009 e vedo persone che non riescono a compilare JPype.

JPype è un progetto morto?

Ci sono altre alternative?

Saluti, David


3
Potresti spiegare perché pensi che Jython e RPC non siano un'opzione per la tua situazione?
Nathan Davis

2
Sembra che nel frattempo ci sia stata una nuova versione di JPype: 0.5.4.2 il 28/07/2011
Joril

Risposte:


51

Ecco il mio riepilogo di questo problema: 5 modi per chiamare Java da Python

http://baojie.org/blog/2014/06/16/call-java-from-python/ ( memorizzato nella cache )

Risposta breve: Jpype funziona abbastanza bene ed è dimostrato in molti progetti (come python-boilerpipe), ma Pyjnius è più veloce e più semplice di JPype

Ho provato Pyjnius / Jnius, JCC, javabridge, Jpype e Py4j.

Py4j è un po 'difficile da usare, poiché è necessario avviare un gateway, aggiungendo un altro livello di fragilità.


135

Puoi anche usare Py4J . C'è un esempio in prima pagina e molta documentazione, ma essenzialmente, chiami i metodi Java dal tuo codice Python come se fossero metodi 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

Al contrario di Jython, una parte di Py4J viene eseguita nella VM Python, quindi è sempre "aggiornata" con l'ultima versione di Python ed è possibile utilizzare librerie che non funzionano bene su Jython (ad esempio, lxml). L'altra parte viene eseguita nella Java VM che si desidera chiamare.

La comunicazione avviene tramite socket invece che JNI e Py4J ha un proprio protocollo (per ottimizzare alcuni casi, per gestire la memoria, ecc.)

Disclaimer: sono l'autore di Py4J


Grazie per il collegamento. sembra un'alternativa open-source a quanto proposto da djna, CodeMesh. Lo guarderò definitivamente. Tuttavia c'è lo stesso problema di CodeMesh, richiede di avviare il processo Java prima e assicurarsi che sia in esecuzione prima di utilizzare python (vedere l'esempio nella pagina web principale del progetto, ListPrinter.java -> main -> GatewayServer.start ( )). Questo è un possibile punto di errore. Continuo a pensare che l'approccio di JPype sia eccellente; solo che sembra un progetto morto.
David Portabella

8
@alvas Mantengo ancora Py4J se è questo che intendevi.
Barthelemy

@Barthelemy, come procedere per l'integrazione se il codice Java dipende da una libreria - opencv nel mio caso?

1
@stack assicurati di aggiungere opencv nel tuo classpath e sarai in grado di accedervi da Python quando avvii GatewayServer.
Barthelemy

Funziona per qualsiasi pacchetto? Ho provato: s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();qui la classe Base64 ha il metodo encode () e decode () e fa parte del pacchetto ch.ethz.ssh2.cryptonel mio file .jar. Ottengofrom py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu

19

Pyjnius.

Documenti: http://pyjnius.readthedocs.org/en/latest/

Github: https://github.com/kivy/pyjnius

Dalla pagina GitHub:

Un modulo Python per accedere alle classi Java come classi Python utilizzando JNI.

PyJNIus è un "Work In Progress".

Veloce panoramica

>>> from jnius import autoclass
>>> autoclass('java.lang.System').out.println('Hello world') Hello world

>>> Stack = autoclass('java.util.Stack')
>>> stack = Stack()
>>> stack.push('hello')
>>> stack.push('world')
>>> print stack.pop() world
>>> print stack.pop() hello

5

Sono su OSX 10.10.2 e sono riuscito a utilizzare JPype.

Ho riscontrato problemi di installazione con Jnius (anche altri lo hanno ), Javabridge installato ma ha dato errori misteriosi quando ho provato a usarlo, PyJ4 ha questo inconveniente di dover avviare prima un server Gateway in Java, JCC non si installava. Infine, JPype ha finito per funzionare. C'è un fork mantenuto di JPype su Github. Ha i principali vantaggi che (a) si installa correttamente e (b) può convertire in modo molto efficiente array java in array numpy (np_arr = java_arr[:] )

Il processo di installazione è stato:

git clone https://github.com/originell/jpype.git
cd jpype
python setup.py install

E dovresti essere in grado di farlo import jpype

La seguente demo ha funzionato:

import jpype as jp
jp.startJVM(jp.getDefaultJVMPath(), "-ea")
jp.java.lang.System.out.println("hello world")
jp.shutdownJVM() 

Quando ho provato a chiamare il mio codice java, ho dovuto prima compilare ( javac ./blah/HelloWorldJPype.java), e ho dovuto cambiare il percorso JVM dal predefinito (altrimenti otterrai errori inspiegabili di "classe non trovata"). Per me, questo significava cambiare il comando startJVM in:

jp.startJVM('/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/MacOS/libjli.dylib', "-ea")
c = jp.JClass('blah.HelloWorldJPype')  
# Where my java class file is in ./blah/HelloWorldJPype.class
...

Un piccolo modulo wrapper per rendere JPype un po 'più facile da usare è qui: github.com/petered/spiking-mlp/blob/master/spiking_mlp/…
Peter

4

Se sei in Python 3, c'è un fork di JPype chiamato JPype1-py3

pip install JPype1-py3

Questo funziona per me su OSX / Python 3.4.3. (Potrebbe essere necessario export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

from jpype import *
startJVM(getDefaultJVMPath(), "-ea")
java.lang.System.out.println("hello world")
shutdownJVM()

4

Ultimamente ho integrato molte cose in Python, incluso Java. Il metodo più affidabile che ho trovato è usare IKVM e un wrapper C #.

IKVM ha una piccola applicazione che ti consente di prendere qualsiasi JAR Java e convertirlo direttamente in DLL .Net. Traduce semplicemente il bytecode JVM in bytecode CLR. Vedi http://sourceforge.net/p/ikvm/wiki/Ikvmc/ per i dettagli.

La libreria convertita si comporta proprio come una libreria C # nativa e puoi usarla senza bisogno della JVM. È quindi possibile creare un progetto wrapper DLL C # e aggiungere un riferimento alla DLL convertita.

È ora possibile creare alcuni stub wrapper che chiamano i metodi che si desidera esporre e contrassegnare tali metodi come DllEport. Vedere https://stackoverflow.com/a/29854281/1977538 per i dettagli.

La DLL wrapper si comporta proprio come una libreria C nativa, con i metodi esportati che assomigliano ai metodi C esportati. Puoi connetterti a loro usando ctype come al solito.

L'ho provato con Python 2.7, ma dovrebbe funzionare anche con 3.0. Funziona su Windows e Linux

Se ti capita di usare C #, questo è probabilmente l'approccio migliore da provare quando si integra quasi tutto in Python.


1
Uhg ... mi hai perso in C #. Non sottovaluterò poiché questa è una possibilità praticabile per alcuni casi, ma questo presuppone sicuramente Windows e molte altre cose.
Jared

2

Sto appena iniziando a usare JPype 0.5.4.2 (luglio 2011) e sembra che funzioni bene ...
Sono su Xubuntu 10.04


1

Presumo che se puoi passare da C ++ a Java, allora sei pronto. Ho visto un prodotto del tipo di cui parli funzionare bene. Come succede quello che abbiamo usato è stato CodeMesh . Non sto specificatamente appoggiando questo fornitore, o facendo alcuna dichiarazione sulla qualità relativa del loro prodotto, ma ho visto che funziona in uno scenario di volume piuttosto elevato.

Direi in generale che, se possibile, consiglierei di evitare l'integrazione diretta tramite JNI, se puoi. Un semplice approccio al servizio REST o un'architettura basata su code tenderà ad essere più semplice da sviluppare e diagnosticare. È possibile ottenere prestazioni abbastanza decenti se si utilizzano con attenzione tali tecnologie disaccoppiate.


RPC (o REST) ​​non è un'opzione per me.
David Portabella

Ciò richiederebbe di avviare il processo Java prima e assicurarsi che sia in esecuzione prima di utilizzare python. Questo è un possibile punto di errore. L'approccio di JPype è eccellente; solo che sembra un progetto morto.
David Portabella

Sto dando consigli generali. JNI è un potenziale campo minato.
djna

0

Attraverso la mia esperienza nel tentativo di eseguire un po 'di codice java dall'interno di Python, in modo simile a come il codice Python viene eseguito all'interno del codice Java in Python, non sono riuscito a trovare una metodologia diretta.

La mia soluzione al mio problema è stata l'esecuzione di questo codice java come script beanshell chiamando l'interprete beanshell come una shell commnad dall'interno del mio codice python dopo aver modificato il codice java in un file temporaneo con i pacchetti e le variabili appropriati.

Se ciò di cui sto parlando è utile in qualche modo, sono lieto di aiutarti a condividere maggiori dettagli delle mie soluzioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.