เรียก Java จาก Python


123

วิธีที่ดีที่สุดในการเรียก java จาก python คืออะไร? (jython และ RPC ไม่ใช่ตัวเลือกสำหรับฉัน)

ฉันเคยได้ยิน JCC: http://pypi.python.org/pypi/JCC/1.9 ตัวสร้างรหัส C ++ สำหรับการเรียก Java จาก C ++ / Python แต่สิ่งนี้ต้องการการรวบรวมทุกการเรียกที่เป็นไปได้ ฉันต้องการวิธีแก้ปัญหาอื่น

ฉันได้ยินเกี่ยวกับ JPype: http://jpype.sourceforge.net/ บทช่วยสอน: 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() 

ดูเหมือนว่าสิ่งที่ฉันต้องการ อย่างไรก็ตามการเปิดตัวครั้งสุดท้ายคือตั้งแต่เดือนมกราคม 2009 และฉันเห็นว่ามีคนรวบรวม JPype ไม่สำเร็จ

JPype เป็นโครงการที่ตายแล้วหรือไม่?

มีทางเลือกอื่นหรือไม่?

ขอแสดงความนับถือเดวิด


3
คุณช่วยอธิบายให้ละเอียดได้ไหมว่าทำไมคุณถึงคิดว่า Jython และ RPC ไม่ใช่ตัวเลือกสำหรับสถานการณ์ของคุณ
Nathan Davis

2
ดูเหมือนว่าในระหว่างนั้นจะมีการเปิดตัว JPype ใหม่: 0.5.4.2 ในวันที่ 2011-07-28
Joril

คำตอบ:


51

นี่คือบทสรุปของฉันเกี่ยวกับปัญหานี้: 5 วิธีในการเรียก Java จาก Python

http://baojie.org/blog/2014/06/16/call-java-from-python/ ( แคช )

คำตอบสั้น ๆ : Jpype ทำงานได้ดีและได้รับการพิสูจน์แล้วในหลายโครงการ (เช่น python-boilerpipe) แต่ Pyjnius นั้นเร็วกว่าและง่ายกว่า JPype

ฉันได้ลอง Pyjnius / Jnius, JCC, javabridge, Jpype และ Py4j

Py4j ใช้งานยากเล็กน้อยเนื่องจากคุณต้องเริ่มต้นเกตเวย์และเพิ่มความเปราะบางอีกชั้น


135

นอกจากนี้คุณยังสามารถใช้Py4J มีตัวอย่างในหน้าแรกและเอกสารประกอบมากมาย แต่โดยพื้นฐานแล้วคุณเพียงแค่เรียกใช้เมธอด Java จากโค้ด python ของคุณราวกับว่าเป็นวิธีการ 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

ซึ่งตรงข้ามกับ Jython ส่วนหนึ่งของ Py4J จะทำงานใน Python VM ดังนั้นจึง "เป็นเวอร์ชันล่าสุด" ของ Python เวอร์ชันล่าสุดอยู่เสมอและคุณสามารถใช้ไลบรารีที่ทำงานบน Jython ได้ไม่ดี (เช่น lxml) ส่วนอื่น ๆ ทำงานใน Java VM ที่คุณต้องการเรียกใช้

การสื่อสารทำผ่านซ็อกเก็ตแทน JNI และ Py4J มีโปรโตคอลของตัวเอง (เพื่อเพิ่มประสิทธิภาพบางกรณีเพื่อจัดการหน่วยความจำ ฯลฯ )

คำเตือน: ฉันเป็นคนเขียน Py4J


ขอบคุณสำหรับลิงค์ ดูเหมือนทางเลือกโอเพนซอร์สสำหรับสิ่งที่ djna เสนอ CodeMesh ฉันจะดูอย่างชัดเจน อย่างไรก็ตามมีปัญหาเช่นเดียวกับใน CodeMesh ต้องเริ่มกระบวนการ Java ก่อนและตรวจสอบให้แน่ใจว่าทำงานก่อนที่จะใช้ python (ดูตัวอย่างในหน้าเว็บหลักของโครงการ ListPrinter.java -> main -> GatewayServer.start ( )) นี่คือจุดที่เป็นไปได้ของความล้มเหลว ฉันยังคิดว่าแนวทางของ JPype นั้นยอดเยี่ยมมาก เพียง แต่ดูเหมือนว่าโครงการที่ตายแล้ว
David Portabella

8
@alvas ฉันยังคงรักษา Py4J ถ้านั่นคือสิ่งที่คุณหมายถึง
Barthelemy

@Barthelemy วิธีการรวมถ้าโค้ด Java ขึ้นอยู่กับไลบรารี - opencv ในกรณีของฉัน

1
@stack ตรวจสอบให้แน่ใจว่าได้เพิ่ม opencv ใน classpath ของคุณแล้วคุณจะสามารถเข้าถึงได้จาก Python เมื่อคุณเริ่ม GatewayServer
Barthelemy

สิ่งนี้ใช้ได้กับแพ็คเกจใด ๆ หรือไม่? ฉันลองแล้ว: ที่s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();นี่คลาส Base64 มีวิธีการเข้ารหัส () และถอดรหัส () และเป็นส่วนหนึ่งของแพ็คเกจch.ethz.ssh2.cryptoในไฟล์. jar ของฉัน ฉันได้รับfrom py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu

19

Pyjnius

เอกสาร: http://pyjnius.readthedocs.org/en/latest/

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

จากหน้า github:

โมดูล Python เพื่อเข้าถึงคลาส Java เป็นคลาส Python โดยใช้ JNI

PyJNIus คือ "งานระหว่างทำ"

ภาพรวมอย่างรวดเร็ว

>>> 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

ฉันใช้ OSX 10.10.2 และประสบความสำเร็จในการใช้ JPype

พบปัญหาการติดตั้งกับ Jnius ( คนอื่น ๆ ก็มีเช่นกัน ) ติดตั้ง Javabridge แต่เกิดข้อผิดพลาดลึกลับเมื่อฉันพยายามใช้ PyJ4 มีความไม่สะดวกที่จะต้องเริ่มเซิร์ฟเวอร์ Gateway ใน Java ก่อน JCC จะไม่ติดตั้ง ในที่สุด JPype ก็จบการทำงาน มีทางแยก JPypeบน Github มีข้อดีที่สำคัญคือ (a) ติดตั้งอย่างถูกต้องและ (b) สามารถแปลงอาร์เรย์ java เป็นอาร์เรย์ numpy ได้อย่างมีประสิทธิภาพ ( np_arr = java_arr[:])

ขั้นตอนการติดตั้งคือ:

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

และคุณควรจะทำได้ import jpype

การสาธิตต่อไปนี้ใช้งานได้:

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

เมื่อฉันพยายามเรียกรหัส java ของตัวเองฉันต้องคอมไพล์ ( javac ./blah/HelloWorldJPype.java) ก่อนและฉันต้องเปลี่ยนเส้นทาง JVM จากค่าเริ่มต้น (มิฉะนั้นคุณจะได้รับข้อผิดพลาด "class not found" ที่อธิบายไม่ได้) สำหรับฉันนี่หมายถึงการเปลี่ยนคำสั่ง startJVM เป็น:

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
...

โมดูลกระดาษห่อเล็ก ๆ ที่จะทำให้ JPype ใช้งานได้ง่ายขึ้นอยู่ที่นี่: github.com/petered/spiking-mlp/blob/master/spiking_mlp/…
Peter

4

หากคุณอยู่ใน Python 3 จะมีทางแยกของ JPype ที่เรียกว่าJPype1-py3

pip install JPype1-py3

สิ่งนี้ใช้ได้กับฉันบน OSX / Python 3.4.3 (คุณอาจต้องexport JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

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

4

เมื่อเร็ว ๆ นี้ฉันได้รวมสิ่งต่างๆมากมายเข้ากับ Python รวมถึง Java ด้วย วิธีที่มีประสิทธิภาพที่สุดที่ฉันพบคือการใช้ IKVM และ C # wrapper

IKVM มีแอปพลิเคชั่นเล็ก ๆ น้อย ๆ ที่ช่วยให้คุณใช้ Java JAR และแปลงเป็น. Net DLL ได้โดยตรง เพียงแค่แปล JVM bytecode เป็น CLR bytecode ดูรายละเอียดที่http://sourceforge.net/p/ikvm/wiki/Ikvmc/

ไลบรารีที่แปลงแล้วจะทำงานเหมือนกับไลบรารี C # ดั้งเดิมและคุณสามารถใช้งานได้โดยไม่ต้องใช้ JVM จากนั้นคุณสามารถสร้างโปรเจ็กต์ C # DLL wrapper และเพิ่มการอ้างอิงไปยัง DLL ที่แปลงแล้ว

ตอนนี้คุณสามารถสร้างต้นขั้วกระดาษห่อที่เรียกเมธอดที่คุณต้องการเปิดเผยและทำเครื่องหมายวิธีการเหล่านั้นเป็น DllEport ดูhttps://stackoverflow.com/a/29854281/1977538สำหรับรายละเอียด

Wrapper DLL ทำหน้าที่เหมือนกับไลบรารี C ดั้งเดิมโดยวิธีการส่งออกจะมีลักษณะเหมือนกับวิธี C ที่ส่งออก คุณสามารถเชื่อมต่อกับพวกเขาโดยใช้ ctype ได้ตามปกติ

ฉันได้ลองใช้กับ Python 2.7 แล้ว แต่ควรใช้กับ 3.0 ได้เช่นกัน ทำงานบน Windows และ Linuxes

หากคุณใช้ C # นี่อาจเป็นแนวทางที่ดีที่สุดที่จะลองใช้เมื่อรวมเกือบทุกอย่างเข้ากับ python


1
เอ่อ ... คุณเสียฉันที่ C # ฉันจะไม่ลงคะแนนเนื่องจากเป็นไปได้ในบางกรณี แต่สิ่งนี้ถือว่า Windows และสิ่งอื่น ๆ อีกมากมาย
Jared

2

ฉันเพิ่งเริ่มใช้ JPype 0.5.4.2 (กรกฎาคม 2011) และดูเหมือนว่ามันจะใช้งานได้ดี ...
ฉันใช้ Xubuntu 10.04


1

ฉันสมมติว่าถ้าคุณได้รับจาก C ++ เป็น Java แสดงว่าคุณพร้อมแล้ว ฉันเคยเห็นผลิตภัณฑ์ชนิดหนึ่งที่คุณกล่าวถึงทำงานได้ดี เมื่อมันเกิดขึ้นอย่างใดอย่างหนึ่งที่เราใช้เป็นCodeMesh ฉันไม่ได้รับรองผู้ขายรายนี้โดยเฉพาะหรือแถลงเกี่ยวกับคุณภาพสัมพัทธ์ของผลิตภัณฑ์ของพวกเขา แต่ฉันเห็นว่ามันใช้งานได้ในสถานการณ์ที่มีปริมาณมาก

ฉันจะพูดโดยทั่วไปว่าถ้าเป็นไปได้ฉันขอแนะนำให้หลีกเลี่ยงการรวมโดยตรงผ่าน JNI ถ้าคุณทำได้ วิธีการบริการ REST แบบง่าย ๆ หรือสถาปัตยกรรมตามคิวมักจะพัฒนาและวินิจฉัยได้ง่ายกว่า คุณจะได้รับความสมบูรณ์แบบที่ดีทีเดียวหากคุณใช้เทคโนโลยีแยกส่วนอย่างระมัดระวัง


RPC (หรือ REST) ​​ไม่ใช่ตัวเลือกสำหรับฉัน
David Portabella

สิ่งนี้จะต้องเริ่มกระบวนการ Java ก่อนและตรวจสอบให้แน่ใจว่ากำลังทำงานอยู่ก่อนที่จะใช้ python นี่คือจุดที่เป็นไปได้ของความล้มเหลว แนวทางของ JPype นั้นยอดเยี่ยมมาก เพียง แต่ดูเหมือนว่าโครงการที่ตายแล้ว
David Portabella

ฉันกำลังให้คำแนะนำทั่วไป JNI เป็นพื้นที่ทุ่นระเบิดที่มีศักยภาพ
djna

0

จากประสบการณ์ของฉันเองในการพยายามเรียกใช้โค้ด java จากภายใน python ia ในลักษณะเดียวกับที่โค้ด python ทำงานภายในโค้ด java ใน python ฉันไม่สามารถค้นหาวิธีการตรงไปตรงมาได้

วิธีแก้ปัญหาของฉันคือการเรียกใช้รหัส java นี้เป็นสคริปต์ beanhell โดยเรียกตัวแปลถั่วเป็นเชลล์คอมมูนจากภายในรหัส python ของฉันหลังจากแก้ไขรหัส java ในไฟล์ชั่วคราวด้วยแพ็คเกจและตัวแปรที่เหมาะสม

หากสิ่งที่ฉันกำลังพูดถึงมีประโยชน์ในด้านใดก็ตามฉันยินดีที่จะช่วยคุณแบ่งปันรายละเอียดเพิ่มเติมเกี่ยวกับวิธีแก้ปัญหาของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.