Wywołanie Javy z Pythona

123

Jaki jest najlepszy sposób wywoływania javy z Pythona? (jython i RPC nie są dla mnie opcją).

Słyszałem o JCC: http://pypi.python.org/pypi/JCC/1.9 generator kodu C ++ do wywoływania Javy z C ++ / Pythona Ale to wymaga kompilacji każdego możliwego wywołania; Wolałbym inne rozwiązanie.

Słyszałem o 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() 

To wygląda na to, czego potrzebuję. Jednak ostatnie wydanie pochodzi ze stycznia 2009 roku i widzę, że ludzie nie potrafią skompilować JPype.

Czy JPype to martwy projekt?

Czy są jakieś inne alternatywy?

Pozdrawiam, David

David Portabella
źródło
3
Czy mógłbyś wyjaśnić, dlaczego uważasz, że Jython i RPC nie są opcją w Twojej sytuacji?
Nathan Davis,
2
Wygląda na to, że w międzyczasie pojawiła się nowa wersja JPype: 0.5.4.2 w dniu 2011-07-28
Joril

Odpowiedzi:

51

Oto moje podsumowanie tego problemu: 5 sposobów wywoływania Javy z Pythona

http://baojie.org/blog/2014/06/16/call-java-from-python/ (w pamięci podręcznej )

Krótka odpowiedź: Jpype działa całkiem nieźle i jest sprawdzony w wielu projektach (takich jak python-boilerpipe), ale Pyjnius jest szybszy i prostszy niż JPype

Wypróbowałem Pyjnius / Jnius, JCC, javabridge, Jpype i Py4j.

Py4j jest trochę trudny w użyciu, ponieważ musisz uruchomić bramę, dodając kolejną warstwę kruchości.

Jie Bao
źródło
135

Możesz także użyć Py4J . Na stronie głównej znajduje się przykład i mnóstwo dokumentacji, ale zasadniczo wywołujesz metody Java z kodu Pythona tak, jakby były metodami Pythona:

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

W przeciwieństwie do Jythona, jedna część Py4J działa na maszynie wirtualnej Python, więc zawsze jest "aktualna" z najnowszą wersją Pythona i możesz używać bibliotek, które nie działają dobrze w Jythonie (np. Lxml). Druga część działa na maszynie wirtualnej Java, którą chcesz wywołać.

Komunikacja odbywa się za pośrednictwem gniazd zamiast JNI, a Py4J ma własny protokół (w celu optymalizacji niektórych przypadków, zarządzania pamięcią itp.)

Zastrzeżenie: jestem autorem Py4J

Barthelemy
źródło
Dzięki za link. wygląda jak otwarta alternatywa dla tego, co zaproponował djna, CodeMesh. Na pewno się temu przyjrzę. Istnieje jednak ten sam problem, co w CodeMesh, wymaga on wcześniejszego uruchomienia procesu Java i upewnienia się, że jest uruchomiony przed użyciem Pythona (zobacz przykład na głównej stronie projektu ListPrinter.java -> main -> GatewayServer.start ( )). Jest to możliwy punkt awarii. Nadal uważam, że podejście JPype jest doskonałe; tylko że wydaje się to martwym projektem.
David Portabella,
8
@alvas Nadal utrzymuję Py4J, jeśli o to ci chodziło.
Barthelemy,
@Barthelemy, jak zabrać się za integrację, jeśli kod Javy jest zależny od biblioteki - w moim przypadku opencv?
1
@stack po prostu upewnij się, że dodałeś opencv do swojej ścieżki klas, a będziesz mieć do niego dostęp z Pythona po uruchomieniu GatewayServer.
Barthelemy
Czy to działa dla każdego pakietu? Próbowałem: s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();tutaj klasa Base64 ma metodę encode () i decode () i jest częścią pakietu ch.ethz.ssh2.cryptow moim pliku .jar. Dostajęfrom py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu
19

Pyjnius.

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

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

Ze strony github:

Moduł Pythona umożliwiający dostęp do klas Java jako klas Pythona przy użyciu JNI.

PyJNIus to „Praca w toku”.

Szybki przegląd

>>> 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
gdw2
źródło
5

Jestem na OSX 10.10.2 i udało mi się użyć JPype.

Wpadłem na problemy z instalacją z Jnius ( inni też ), Javabridge zainstalował się, ale dał tajemnicze błędy, kiedy próbowałem go użyć, PyJ4 ma tę niedogodność, że trzeba najpierw uruchomić serwer Gateway w Javie, JCC nie mógł zainstalować. Wreszcie JPype zaczął działać. Na Githubie jest utrzymywany fork JPype . Ma główne zalety, że (a) instaluje się poprawnie i (b) może bardzo wydajnie konwertować tablice java na tablice numpy ( np_arr = java_arr[:])

Proces instalacji wyglądał następująco:

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

I powinieneś być w stanie import jpype

Następujące demo zadziałało:

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

Kiedy próbowałem wywołać swój własny kod java, musiałem najpierw skompilować ( javac ./blah/HelloWorldJPype.java) i zmienić ścieżkę JVM z domyślnej (w przeciwnym razie pojawią się niewytłumaczalne błędy „nie znaleziono klasy”). Dla mnie oznaczało to zmianę polecenia startJVM na:

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
...
Piotr
źródło
Mały moduł opakowujący, dzięki któremu JPype jest nieco łatwiejszy w użyciu, jest tutaj: github.com/petered/spiking-mlp/blob/master/spiking_mlp/ ...
Peter
4

Jeśli jesteś w Pythonie 3, istnieje rozwidlenie JPype o nazwie JPype1-py3

pip install JPype1-py3

To działa dla mnie na OSX / Python 3.4.3. (Może być konieczne export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

from jpype import *
startJVM(getDefaultJVMPath(), "-ea")
java.lang.System.out.println("hello world")
shutdownJVM()
k107
źródło
4

Ostatnio integrowałem wiele rzeczy z Pythonem, w tym Javę. Najbardziej niezawodną metodą, jaką znalazłem, jest użycie IKVM i opakowania C #.

IKVM ma zgrabną małą aplikację, która pozwala na pobranie dowolnego Java JAR i konwersję go bezpośrednio do .Net DLL. Po prostu tłumaczy kod bajtowy maszyny JVM na kod bajtowy CLR. Szczegółowe informacje można znaleźć pod adresem http://sourceforge.net/p/ikvm/wiki/Ikvmc/ .

Przekonwertowana biblioteka zachowuje się tak jak natywna biblioteka C # i można jej używać bez konieczności korzystania z maszyny JVM. Następnie można utworzyć projekt opakowania DLL C # i dodać odwołanie do przekonwertowanej biblioteki DLL.

Możesz teraz utworzyć kilka kodów pośredniczących opakowania, które wywołują metody, które chcesz ujawnić, i oznaczyć te metody jako DllEport. Szczegółowe informacje można znaleźć pod adresem https://stackoverflow.com/a/29854281/1977538 .

Otaczająca biblioteka DLL działa jak natywna biblioteka C, a wyeksportowane metody wyglądają tak samo, jak wyeksportowane metody C. Możesz połączyć się z nimi za pomocą ctype jak zwykle.

Wypróbowałem to z Pythonem 2.7, ale powinno działać również z 3.0. Działa na Windows i Linux

Jeśli zdarzy ci się używać C #, jest to prawdopodobnie najlepsze podejście do wypróbowania podczas integracji prawie wszystkiego z Pythonem.

Rob Deary
źródło
1
Uhg ... straciłeś mnie w C #. Nie będę głosował przeciw, ponieważ w niektórych przypadkach jest to realna możliwość, ale to zdecydowanie zakłada system Windows i wiele innych rzeczy.
Jared
2

Dopiero zaczynam używać JPype 0.5.4.2 (lipiec 2011) i wygląda na to, że działa dobrze ...
Jestem na Xubuntu 10.04

Joril
źródło
1

Zakładam, że jeśli możesz przejść z C ++ do Java, to wszystko jest ustawione. Widziałem produkt, o którym wspomniałeś, że działa dobrze. Tak się składa, że ​​użyliśmy CodeMesh . Nie popieram specjalnie tego dostawcy ani nie wypowiadam się na temat względnej jakości jego produktu, ale widziałem, jak działa on w scenariuszu o dość dużym wolumenie.

Powiedziałbym ogólnie, że jeśli to w ogóle możliwe, zalecałbym unikanie bezpośredniej integracji przez JNI, jeśli możesz. Niektóre proste podejście do usług REST lub architektura oparta na kolejkach będą zwykle prostsze do opracowania i diagnozowania. Możesz uzyskać całkiem przyzwoitą wydajność, jeśli ostrożnie używasz takich oddzielonych technologii.

djna
źródło
RPC (lub REST) ​​nie jest dla mnie opcją.
David Portabella,
Wymagałoby to wcześniejszego uruchomienia procesu Java i upewnienia się, że jest uruchomiony przed użyciem języka Python. Jest to możliwy punkt awarii. Podejście JPype jest doskonałe; tylko że wydaje się to martwym projektem.
David Portabella,
Daję ogólne rady. JNI to potencjalne pole minowe.
djna,
0

Z własnego doświadczenia, próbując uruchomić kod java z poziomu pythona m.in. w sposób podobny do tego, jak kod python działa w kodzie java w pythonie, nie mogłem znaleźć prostej metodologii.

Rozwiązaniem mojego problemu było uruchomienie tego kodu java jako skryptów behellowych przez wywołanie interpretera behellu jako komendy powłoki z mojego kodu Pythona po edycji kodu java w pliku tymczasowym z odpowiednimi pakietami i zmiennymi.

Jeśli to, o czym mówię, jest w jakikolwiek sposób pomocne, z chęcią pomogę Ci podzielić się szczegółami moich rozwiązań.

shady alaa
źródło