Gọi Java từ Python


123

Cách tốt nhất để gọi java từ python là gì? (jython và RPC không phải là một lựa chọn cho tôi).

Tôi đã nghe nói về JCC: http://pypi.python.org/pypi/JCC/1.9 một trình tạo mã C ++ để gọi Java từ C ++ / Python Nhưng điều này yêu cầu biên dịch mọi lệnh gọi có thể; Tôi muốn một giải pháp khác.

Tôi đã nghe về JPype: http://jpype.sourceforge.net/ hướng dẫn: 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() 

Điều này giống như những gì tôi cần. Tuy nhiên, bản phát hành cuối cùng là từ tháng 1 năm 2009 và tôi thấy mọi người không biên dịch được JPype.

JPype có phải là một dự án đã chết?

Còn lựa chọn nào nữa ko?

Trân trọng, David


3
Bạn có thể giải thích thêm tại sao bạn nghĩ rằng Jython và RPC không phải là một lựa chọn cho tình huống của bạn?
Nathan Davis

2
Có vẻ như trong thời gian chờ đợi đã có một bản phát hành JPype mới: 0.5.4.2 vào ngày
Joril

Câu trả lời:


51

Đây là bản tóm tắt của tôi về vấn đề này: 5 cách gọi Java từ Python

http://baojie.org/blog/2014/06/16/call-java-from-python/ (đã lưu trong bộ nhớ cache )

Câu trả lời ngắn gọn: Jpype hoạt động khá tốt và được chứng minh trong nhiều dự án (chẳng hạn như python-boilerpipe), nhưng Pyjnius nhanh hơn và đơn giản hơn JPype

Tôi đã thử Pyjnius / Jnius, JCC, javabridge, Jpype và Py4j.

Py4j hơi khó sử dụng vì bạn cần phải bắt đầu một cổng vào, thêm một lớp mỏng manh khác.


135

Bạn cũng có thể sử dụng Py4J . Có một ví dụ trên trang chủ và rất nhiều tài liệu, nhưng về cơ bản, bạn chỉ cần gọi các phương thức Java từ mã python của mình như thể chúng là phương thức 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

Trái ngược với Jython, một phần của Py4J chạy trong Python VM vì vậy nó luôn được "cập nhật" với phiên bản Python mới nhất và bạn có thể sử dụng các thư viện không chạy tốt trên Jython (ví dụ: lxml). Phần khác chạy trong máy ảo Java mà bạn muốn gọi.

Giao tiếp được thực hiện thông qua các ổ cắm thay vì JNI và Py4J có giao thức riêng (để tối ưu hóa các trường hợp nhất định, để quản lý bộ nhớ, v.v.)

Tuyên bố từ chối trách nhiệm: Tôi là tác giả của Py4J


Cảm ơn các liên kết. nó trông giống như một giải pháp thay thế mã nguồn mở cho những gì djna đề xuất, CodeMesh. Tôi chắc chắn sẽ xem xét nó. Tuy nhiên, có một vấn đề tương tự như trong CodeMesh, nó yêu cầu khởi động quy trình Java trước đó và đảm bảo rằng nó đang chạy trước khi sử dụng python (xem ví dụ trong trang web chính của dự án, ListPrinter.java -> main -> GatewayServer.start ( )). Đây là một điểm có thể thất bại. Tôi vẫn nghĩ rằng cách tiếp cận của JPype là tuyệt vời; chỉ rằng nó có vẻ như là một dự án chết.
David Portabella

8
@alvas Tôi vẫn duy trì Py4J nếu đó là ý của bạn.
Barthelemy

@Barthelemy, làm thế nào để tiếp tục tích hợp nếu mã Java phụ thuộc vào thư viện - opencv trong trường hợp của tôi?

1
@stack chỉ cần đảm bảo thêm opencv trong classpath của bạn và bạn sẽ có thể truy cập nó từ Python khi khởi động GatewayServer.
Barthelemy

Điều này có làm việc cho bất kỳ gói nào không? Tôi đã thử: s = gateway.jvm.ch.ethz.ssh2.crypto.Base64() bt_out = s.decode();Ở đây lớp Base64 có phương thức encode () và decode () và là một phần của gói ch.ethz.ssh2.cryptotrong tệp .jar của tôi. Tôi nhận đượcfrom py4j.reflection import MethodInvoker ImportError: No module named reflection
Vishal Sahu

19

Pyjnius.

Tài liệu: http://pyjnius.readthedocs.org/en/latest/

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

Từ trang github:

Một mô-đun Python để truy cập các lớp Java dưới dạng các lớp Python bằng JNI.

PyJNIus là một "Công việc Đang được Tiến hành".

Tổng quan nhanh

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

Tôi đang sử dụng OSX 10.10.2 và đã thành công khi sử dụng JPype.

Gặp sự cố cài đặt với Jnius ( những người khác cũng vậy ), Javabridge đã cài đặt nhưng gặp lỗi bí ẩn khi tôi cố gắng sử dụng nó, PyJ4 có sự bất tiện này là phải khởi động máy chủ Gateway bằng Java trước, JCC sẽ không cài đặt. Cuối cùng, JPype đã hoạt động. Có một nhánh của JPype được duy trì trên Github. Nó có những ưu điểm chính là (a) nó cài đặt đúng cách và (b) nó có thể chuyển đổi rất hiệu quả các mảng java thành mảng numpy ( np_arr = java_arr[:])

Quá trình cài đặt là:

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

Và bạn sẽ có thể import jpype

Bản demo sau đã hoạt động:

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

Khi tôi thử gọi mã java của riêng mình, trước tiên tôi phải biên dịch ( javac ./blah/HelloWorldJPype.java) và tôi phải thay đổi đường dẫn JVM từ mặc định (nếu không bạn sẽ nhận được lỗi "không tìm thấy lớp" không thể giải thích được). Đối với tôi, điều này có nghĩa là thay đổi lệnh startJVM thành:

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

Một mô-đun trình bao bọc nhỏ để giúp JPype dễ sử dụng hơn một chút tại đây: github.com/petered/spiking-mlp/blob/master/spiking_mlp/…
Peter

4

Nếu bạn đang sử dụng Python 3, có một nhánh của JPype được gọi là JPype1-py3

pip install JPype1-py3

Điều này phù hợp với tôi trên OSX / Python 3.4.3. (Bạn có thể cần export JAVA_HOME=/Library/Java/JavaVirtualMachines/your-java-version)

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

4

Gần đây tôi đã tích hợp rất nhiều thứ vào Python, bao gồm cả Java. Phương pháp mạnh mẽ nhất mà tôi đã tìm thấy là sử dụng IKVM và trình bao bọc C #.

IKVM có một ứng dụng nhỏ gọn gàng cho phép bạn sử dụng bất kỳ Java JAR nào và chuyển đổi trực tiếp sang .Net DLL. Nó chỉ đơn giản là dịch mã byte JVM sang mã byte CLR. Xem http://sourceforge.net/p/ikvm/wiki/Ikvmc/ để biết chi tiết.

Thư viện được chuyển đổi hoạt động giống như thư viện C # gốc và bạn có thể sử dụng nó mà không cần JVM. Sau đó, bạn có thể tạo một dự án trình bao bọc C # DLL và thêm một tham chiếu đến DLL đã chuyển đổi.

Bây giờ bạn có thể tạo một số gốc của trình bao bọc gọi các phương thức mà bạn muốn hiển thị và đánh dấu các phương thức đó là DllEport. Xem https://stackoverflow.com/a/29854281/1977538 để biết chi tiết.

DLL của trình bao bọc hoạt động giống như một thư viện C gốc, với các phương thức được xuất trông giống như các phương thức C được xuất. Bạn có thể kết nối với họ bằng ctype như bình thường.

Tôi đã thử nó với Python 2.7, nhưng nó cũng sẽ hoạt động với 3.0. Hoạt động trên Windows và Linuxes

Nếu bạn tình cờ sử dụng C #, thì đây có lẽ là cách tiếp cận tốt nhất để thử khi tích hợp hầu hết mọi thứ vào python.


1
Uhg ... bạn đã đánh mất tôi ở C #. Tôi sẽ không phản đối vì đây là một khả năng khả thi đối với một số trường hợp, nhưng điều này chắc chắn giả định Windows và nhiều thứ khác.
Jared

2

Tôi mới bắt đầu sử dụng JPype 0.5.4.2 (tháng 7 năm 2011) và có vẻ như nó hoạt động tốt ...
Tôi đang sử dụng Xubuntu 10.04


1

Tôi giả định rằng nếu bạn có thể chuyển từ C ++ sang Java thì bạn đã sẵn sàng. Tôi đã thấy một sản phẩm thuộc loại mà bạn đề cập hoạt động tốt. Khi nó xảy ra, một trong những chúng tôi sử dụng là CodeMesh . Tôi không xác nhận cụ thể nhà cung cấp này hoặc đưa ra bất kỳ tuyên bố nào về chất lượng tương đối của sản phẩm của họ, nhưng tôi đã thấy nó hoạt động trong một kịch bản khối lượng khá lớn.

Tôi sẽ nói chung rằng nếu có thể, tôi khuyên bạn nên tránh tích hợp trực tiếp qua JNI nếu bạn có thể. Một số cách tiếp cận dịch vụ REST đơn giản hoặc kiến ​​trúc dựa trên hàng đợi sẽ có xu hướng phát triển và chẩn đoán đơn giản hơn. Bạn có thể đạt được hiệu suất khá tốt nếu sử dụng các công nghệ tách rời như vậy một cách cẩn thận.


RPC (hoặc REST) ​​không phải là một lựa chọn cho tôi.
David Portabella

Điều này sẽ yêu cầu bắt đầu quy trình Java trước đó và đảm bảo rằng nó đang chạy trước khi sử dụng python. Đây là một điểm có thể thất bại. Cách tiếp cận của JPype là tuyệt vời; chỉ rằng nó có vẻ như là một dự án chết.
David Portabella

Tôi đang đưa ra lời khuyên chung. JNI là một bãi mìn tiềm năng.
djna

0

Qua kinh nghiệm của riêng tôi khi cố gắng chạy một số mã java từ bên trong python ia theo cách tương tự như cách mã python chạy trong mã java trong python, tôi không thể tìm thấy phương pháp chuyển tiếp thẳng.

Giải pháp của tôi cho vấn đề của tôi là chạy mã java này dưới dạng tập lệnh vỏ đậu bằng cách gọi trình thông dịch vỏ đậu dưới dạng dấu phẩy vỏ từ trong mã python của tôi sau khi chỉnh sửa mã java trong tệp tạm thời với các gói và biến thích hợp.

Nếu những gì tôi đang nói là hữu ích theo bất kỳ cách nào, tôi rất vui được giúp bạn chia sẻ thêm chi tiết về các giải pháp của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.