Câu trả lời:
Jython: Python cho Nền tảng Java - http://www.jython.org/index.html
Bạn có thể dễ dàng gọi các hàm python từ mã Java với Jython. Điều đó miễn là bản thân mã python của bạn chạy trong jython, tức là không sử dụng một số tiện ích mở rộng c không được hỗ trợ.
Nếu điều đó phù hợp với bạn, đó chắc chắn là giải pháp đơn giản nhất mà bạn có thể nhận được. Nếu không, bạn có thể sử dụng org.python.util.PythonInterpreter
từ hỗ trợ trình thông dịch Java6 mới.
Một ví dụ đơn giản từ đỉnh đầu của tôi - nhưng sẽ hiệu quả, tôi hy vọng: (không kiểm tra lỗi được thực hiện cho ngắn gọn)
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("import sys\nsys.path.append('pathToModules if they are not there by default')\nimport yourModule");
// execute a function that takes a string and returns a string
PyObject someFunc = interpreter.get("funcName");
PyObject result = someFunc.__call__(new PyString("Test!"));
String realResult = (String) result.__tojava__(String.class);
Này, tôi nghĩ tôi sẽ nhập câu trả lời của mình cho điều này mặc dù nó đã muộn. Tôi nghĩ rằng có một số điều quan trọng cần xem xét đầu tiên với mức độ mạnh mẽ mà bạn muốn có liên kết giữa java và python.
Trước hết Bạn chỉ muốn gọi các hàm hay bạn thực sự muốn mã python thay đổi dữ liệu trong các đối tượng java của mình? Cái này rất quan trọng. Nếu bạn chỉ muốn gọi một số mã python có hoặc không có đối số, thì điều đó không khó lắm. Nếu các lập luận của bạn là sơ khai, nó thậm chí còn dễ dàng hơn. Tuy nhiên, nếu bạn muốn lớp java thực hiện các hàm thành viên trong python, hàm này thay đổi dữ liệu của đối tượng java, thì điều này không dễ dàng hoặc dễ dàng.
Thứ hai là chúng ta đang nói về cpython hay sẽ làm jython? Tôi sẽ nói cpython là nơi của nó tại! Tôi sẽ ủng hộ đây là lý do tại sao python rất khôngol! Tuy nhiên, có tính trừu tượng cao như vậy có thể truy cập vào c, c ++ khi cần thiết. Hãy tưởng tượng nếu bạn có thể có điều đó trong java. Câu hỏi này thậm chí không đáng để hỏi liệu jython có ổn không vì dù sao thì nó cũng dễ dàng.
Vì vậy, tôi đã chơi với các phương pháp sau và liệt kê chúng từ dễ đến khó:
Java sang Jython
Ưu điểm: Dễ dàng. Có tham chiếu thực tế đến các đối tượng java
Nhược điểm: Không có CPython, Cực kỳ chậm!
Jython từ java quá dễ dàng, và nếu điều này thực sự đủ thì tuyệt vời. Tuy nhiên nó rất chậm và không có cpython! Cuộc sống có đáng sống không khi không có cpython Tôi không nghĩ vậy! Bạn có thể dễ dàng có mã python triển khai các chức năng thành viên của bạn cho các đối tượng java.
Java sang Jython đến CPython qua Pyro
Pyro là mô-đun đối tượng từ xa cho python. Bạn có một số đối tượng trên trình thông dịch cpython và bạn có thể gửi cho nó các đối tượng được chuyển qua tuần tự hóa và nó cũng có thể trả về các đối tượng thông qua phương thức này. Lưu ý rằng nếu bạn gửi một đối tượng python được tuần tự hóa từ jython và sau đó gọi một số hàm thay đổi dữ liệu trong các thành viên của nó, thì bạn sẽ không thấy những thay đổi đó trong java. Bạn chỉ cần nhớ gửi lại dữ liệu mà bạn muốn từ pyro. Tôi tin rằng đây là cách dễ nhất để đạt được cpython! Bạn không cần bất kỳ jni hoặc jna hoặc swig hoặc .... Bạn không cần biết bất kỳ c, hoặc c ++ nào. kool hả?
Ưu điểm: Truy cập cpython, không khó như các phương pháp sau
Nhược điểm: Không thể thay đổi dữ liệu thành viên của các đối tượng java trực tiếp từ python. Có phần gián tiếp, (jython là người đàn ông trung gian).
Java sang C / C ++ qua JNI / JNA / SWIG sang Python thông qua trình thông dịch nhúng (có thể sử dụng Thư viện BOOST?)
OMG phương pháp này không dành cho những người yếu tim. Và tôi có thể nói với bạn rằng tôi đã mất rất nhiều thời gian để đạt được điều này với một phương pháp tốt. Lý do chính mà bạn muốn làm điều này là để bạn có thể chạy mã cpython được kiểm soát hoàn toàn trên đối tượng java của bạn. Có những điều chính cần cân nhắc trước khi quyết định thử ăn bánh mì java (giống tinh tinh) với python (giống ngựa). Thứ nhất nếu bạn gặp sự cố trình thông dịch sẽ tắt cho chương trình của bạn! Và đừng khiến tôi bắt đầu về các vấn đề đồng thời! Ngoài ra, có allot allot của nồi hơi, tôi tin rằng tôi đã tìm thấy cấu hình tốt nhất để giảm thiểu nồi hơi này nhưng nó vẫn là allot! Vì vậy, làm thế nào để tiếp tục điều này: Hãy xem xét rằng C ++ là trung gian của bạn, các đối tượng của bạn thực sự là các đối tượng c ++! Thật tốt khi bạn biết điều đó ngay bây giờ. Chỉ cần viết đối tượng của bạn như thể chương trình của bạn như trong cpp không phải java, với dữ liệu bạn muốn truy cập từ cả hai thế giới. Sau đó, bạn có thể sử dụng trình tạo trình bao bọc được gọi là swig (http://www.swig.org/Doc1.3/Java.html ) để làm cho nó có thể truy cập được vào java và biên dịch một dll mà bạn gọi là System.load (tên dll ở đây) trong java. Hãy làm việc này trước, sau đó chuyển sang phần khó! Để truy cập python, bạn cần phải nhúng một trình thông dịch. Trước hết tôi khuyên bạn nên thực hiện một số chương trình thông dịch viên chào hay hướng dẫn này Nhúng python trong C / C . Một khi bạn đã làm việc đó, đã đến lúc làm cho con ngựa và con khỉ nhảy múa! Bạn có thể gửi đối tượng c ++ cho python qua [boost] [3]. Tôi biết tôi đã không đưa cho bạn con cá, chỉ nói cho bạn biết nơi để tìm con cá. Một số gợi ý cần lưu ý khi biên dịch.
Khi bạn biên dịch boost, bạn sẽ cần phải biên dịch một thư viện được chia sẻ. Và bạn cần phải bao gồm và liên kết đến những thứ bạn cần từ jdk, tức là functionst.lib, jvm.lib, (bạn cũng sẽ cần client jvm.dll trong đường dẫn của mình khi khởi chạy ứng dụng) Cũng như python27.lib hoặc bất cứ thứ gì và boost_python-vc100-mt-1_55.lib. Sau đó, bao gồm Python / include, jdk / include, boost và chỉ sử dụng các thư viện được chia sẻ (dlls), nếu không thì boost sẽ bị chảy nước mắt. Và tôi biết. Có rất nhiều cách mà điều này có thể trở nên chua chát. Vì vậy, hãy đảm bảo rằng bạn hoàn thành từng việc từng khối một. Sau đó ghép chúng lại với nhau.
Thật không thông minh khi có mã python bên trong java. Bọc mã python của bạn bằng flask hoặc khuôn khổ web khác để biến nó thành một microservice. Làm cho chương trình java của bạn có thể gọi microservice này (ví dụ: qua REST).
Thông báo cho tôi, điều này rất đơn giản và sẽ giúp bạn tiết kiệm rất nhiều vấn đề. Và các mã được ghép nối lỏng lẻo để chúng có thể mở rộng.
Cập nhật vào ngày 24 tháng 3 năm 2020: Theo nhận xét của @ stx, cách tiếp cận trên không phù hợp để truyền dữ liệu lớn giữa máy khách và máy chủ. Đây là một cách tiếp cận khác mà tôi đề xuất: Kết nối Python và Java với Rust (C / C ++ cũng ok). https://medium.com/@shmulikamar/https-medium-com-shmulikamar-connecting-python-and-java-with-rust-11c256a1dfb0
Đây là một thư viện cho phép bạn viết các tập lệnh python của mình một lần và quyết định phương pháp tích hợp nào (Jython, CPython / PyPy qua Jep và Py4j) để sử dụng trong thời gian chạy:
https://github.com/subes/invesdwin-context-python
Vì mỗi phương pháp có những lợi ích / nhược điểm riêng như được giải thích trong liên kết.
Nó phụ thuộc vào những gì bạn có nghĩa là các chức năng python? nếu chúng được viết bằng cpython, bạn không thể gọi trực tiếp chúng, bạn sẽ phải sử dụng JNI , nhưng nếu chúng được viết bằng Jython, bạn có thể dễ dàng gọi chúng từ java, vì jython cuối cùng tạo ra mã byte java.
Bây giờ khi tôi nói được viết bằng cpython hoặc jython, nó không có ý nghĩa gì nhiều vì python là python và hầu hết mã sẽ chạy trên cả hai triển khai trừ khi bạn đang sử dụng các thư viện cụ thể dựa trên cpython hoặc java.
xem tại đây cách sử dụng trình thông dịch Python trong Java.
GraalVM là một lựa chọn tốt. Tôi đã thực hiện kết hợp Java + Javascript với GraalVM cho thiết kế microservice (Java với phản chiếu Javascript). Gần đây, họ đã thêm hỗ trợ cho python, tôi đặc biệt muốn thử với cộng đồng của nó đã trở nên lớn mạnh như thế nào trong những năm qua.
Bạn có thể gọi bất kỳ ngôn ngữ nào từ java bằng Java Native Interface
Jython có một số hạn chế:
Có một số khác biệt. Đầu tiên, các chương trình Jython không thể sử dụng các mô-đun mở rộng CPython được viết bằng C. Các mô-đun này thường có các tệp có phần mở rộng .so, .pyd hoặc .dll. Nếu bạn muốn sử dụng một mô-đun như vậy, bạn nên tìm một mô-đun tương đương được viết bằng Python hoặc Java thuần túy. Mặc dù về mặt kỹ thuật, việc hỗ trợ các phần mở rộng như vậy là khả thi - IronPython làm như vậy - không có kế hoạch làm như vậy trong Jython.
Phân phối các tập lệnh Python của tôi dưới dạng tệp JAR với Jython?
bạn có thể chỉ cần gọi các tập lệnh python (hoặc tập lệnh bash hoặc Perl) từ Java bằng cách sử dụng Runtime hoặc ProcessBuilder và chuyển đầu ra trở lại Java:
Chạy một tập lệnh bash shell trong java
java runtime.getruntime () nhận đầu ra từ việc thực hiện một chương trình dòng lệnh
Điều này cung cấp một cái nhìn tổng quan khá tốt về các tùy chọn hiện tại. Một số trong số đó được đặt tên trong các câu trả lời khác. Jython không thể sử dụng được cho đến khi họ quyết định triển khai Python 3.x và nhiều dự án khác đang hình thành phía python và muốn truy cập java. Nhưng vẫn còn một số tùy chọn, để đặt tên cho một cái gì đó chưa được đặt tên: gRPC