在 Java 中调用 Python?
- 2025-01-06 08:32:00
- admin 原创
- 168
问题描述:
我想知道是否可以使用 Jython 从 Java 代码调用 Python 函数,或者只能从 Python 调用 Java 代码?
解决方案 1:
Jython:用于 Java 平台的 Python - http://www.jython.org/index.html
您可以使用 Jython 轻松地从 Java 代码调用 Python 函数。只要您的 Python 代码本身在 Jython 下运行,即不使用一些不受支持的 C 扩展。
如果这对您有用,那么这无疑是您能得到的最简单的解决方案。否则,您可以使用org.python.util.PythonInterpreter
新的 Java6 解释器支持。
我脑海中浮现出一个简单的例子 - 但我希望它能够起作用:(为了简洁起见,没有进行错误检查)
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("import sys
sys.path.append('pathToModules if they are not there by default')
import 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);
截至 2021 年,Jython 不再支持 Python 3.x
解决方案 2:
我认为首先要考虑一些重要的事情,即你希望 Java 和 Python 之间的联系有多紧密。
首先, 您只想调用函数,还是真的想让 Python 代码更改 Java 对象中的数据?这非常重要。如果您只想调用一些带参数或不带参数的 Python 代码,那么这并不难。如果您的参数是原语,那么它会变得更加容易。但是,如果您想让 Java 类在 Python 中实现成员函数,从而更改 Java 对象的数据,那么这并不那么容易或直接。
其次,我们是在谈论 CPython 吗,还是 Jython 可以?我会说 CPython 就是它的强项!我主张这就是 Python 如此酷的原因!虽然具有如此高的抽象性,但在需要时可以访问 C 或 C++。想象一下,如果你可以在 Java 中实现这一点。如果 Jython 可以,这个问题甚至不值得问,因为无论如何它都很容易。
因此我尝试了以下方法,并按易到难的顺序列出它们:
Java 到 Jython
优点:非常简单。有对 Java 对象的实际引用
缺点:没有 CPython,非常慢!
Java 中的 Jython 非常简单,如果这真的足够了,那就太好了。但是它非常慢,而且没有 CPython!没有 CPython 生活还值得过吗?我不这么认为!您可以轻松地让 Python 代码为您的 Java 对象实现成员函数。
通过 Pyro 从 Java 到 Jython 到 CPython
Pyro 是 Python 的远程对象模块。CPython 解释器上有一些对象,您可以向其发送通过序列化传输的对象,它也可以通过此方法返回对象。请注意,如果您从 Jython 发送序列化的 Python 对象,然后调用一些更改其成员中数据的函数,那么您将不会在 Java 中看到这些更改。您只需要记住从 Pyro 发回您想要的数据。我相信这是访问 CPython 的最简单方法!您不需要任何 JNI 或 JNA 或 SWIG 或......您不需要了解任何 C 或 C++。很酷吧?
优点:
访问 CPython
并不像以下方法那么困难
缺点:
无法直接从 Python 更改 Java 对象的成员数据
有点间接(Jython 是中间人)
通过 JNI/JNA/SWIG 将 Java 转换为 C/C++,再通过嵌入式解释器将 Java 转换为 Python(也许使用 BOOST 库?)
天哪,这个方法不适合胆小的人。我可以告诉你,我花了很长时间才找到一个像样的方法来实现这一点。你想这样做的主要原因是,这样你就可以运行 CPython 代码,完全控制你的 java 对象。在决定尝试将 Java(就像一只黑猩猩)与 Python(就像一匹马)杂交之前,需要考虑一些重要的事情。首先,如果你让解释器崩溃,那么你的程序就完蛋了!不要让我开始讨论并发问题!此外,还有很多锅炉,我相信我已经找到了最小化这个锅炉的最佳配置,但仍然很多!那么如何做到这一点:考虑 C++ 是你的中间人,你的对象实际上是 C++ 对象!很高兴你现在知道了。只需编写你的对象,就好像你的程序是用 C++ 而不是 Java 编写的,使用你想从两个世界访问的数据。然后,你可以使用名为SWIG 的包装器生成器使其可供 java 访问,并编译一个你在 Java 中调用 () 的 dll System.load(dllNameHere)
。先让它运行起来,然后再开始最难的部分!要使用 Python,您需要嵌入一个解释器。首先,我建议做一些 hello 解释器程序或本教程在 C/C 中嵌入 Python。一旦您让它运行起来,就该让马和猴子跳舞了!您可以通过 boost 将您的 C++ 对象发送到 Python。我知道我没有给您鱼,只是告诉您在哪里可以找到鱼。编译时要注意一些指针。
编译 boost 时,您需要编译一个共享库。并且您需要包含并链接到 jdk 中所需的内容,即 jawt.lib、jvm.lib(启动应用程序时,您还需要在路径中包含客户端 jvm.dll)以及 python27.lib 或其他内容和 boost_python-vc100-mt-1_55.lib。然后包含 Python/include、jdk/include、boost,并且仅使用共享库(dll),否则 boost 会很麻烦。是的,我知道。有很多方法可能会出错。因此,请确保您逐块完成每件事。然后将它们放在一起。
解决方案 3:
在 Java 中嵌入 Python 代码并不明智。使用 Flask 或其他 Web 框架包装 Python 代码,使其成为微服务。这样,您的 Java 程序就可以调用此微服务(例如通过 REST)。
这种方法很简单,可以帮你省去很多麻烦。而且代码是松散耦合的,因此可扩展性好。
2020 年 3 月 24 日更新:根据 @stx 的评论,上述方法不适合客户端和服务器之间的大量数据传输。这是我推荐的另一种方法:使用 Rust 连接 Python 和 Java(C/C++ 也可以)。https
://medium.com/@shmulikamar/https-medium-com-shmulikamar-connecting-python-and-java-with-rust-11c256a1dfb0
解决方案 4:
有几个答案提到你可以使用 JNI 或 JNA 来访问 cpython,但我不建议从头开始,因为已经有可以从 java 访问 cpython 的开源库。例如:
杰普
日元
解决方案 5:
GraalVM是个不错的选择。我曾使用 GraalVM 进行 Java+Javascript 组合微服务设计(Java 和 Javascript 反射)。他们最近添加了对 Python 的支持,我会尝试一下,尤其是考虑到多年来它的社区发展如此之大。
2021 年 6 月更新
https://www.graalvm.org/reference-manual/python/说
GraalVM 提供兼容 Python 3.8 的运行时。GraalVM Python 运行时的主要目标是支持 SciPy 及其组成库,以及与丰富的 Python 生态系统中的其他数据科学和机器学习库配合使用。目前,Python 运行时可供实验和好奇的最终用户使用。
解决方案 6:
这里有一个库,可以让您编写一次 Python 脚本并决定在运行时使用哪种集成方法(Jython、通过 Jep 的 CPython/PyPy 和 Py4j):
https://github.com/subes/invesdwin-context-python
因为每种方法都有其优点/缺点,如链接中所述。
(3 个模块:jep、Py4J、jython)
解决方案 7:
这取决于你所说的 python 函数是什么意思?如果它们是用cpython编写的,你就不能直接调用它们,而必须使用JNI ,但如果它们是用Jython编写的,你可以轻松地从 java 调用它们,因为 jython 最终会生成 java 字节码。
现在,当我说用 cpython 或 jython 编写时,这没有多大意义,因为 python 就是 python,并且大多数代码将在两种实现上运行,除非您使用依赖于 cpython 或 java 的特定库。
请参阅此处了解如何在 Java 中使用 Python 解释器。
解决方案 8:
根据您的要求,像XML-RPC这样的选项可能会有用,它可以用来远程调用几乎任何支持该协议的语言中的函数。
解决方案 9:
Jython 有一些限制:
存在许多差异。首先,Jython 程序不能使用用 C 编写的 CPython 扩展模块。这些模块通常具有扩展名为 .so、.pyd 或 .dll 的文件。如果要使用这样的模块,则应寻找用纯 Python 或 Java 编写的等效模块。虽然从技术上讲支持此类扩展是可行的 - IronPython 就是这样做的 - 但 Jython 中没有计划这样做。
使用 Jython 将我的 Python 脚本作为 JAR 文件分发?
您可以简单地使用 Runtime 或 ProcessBuilder 从 Java 调用 python 脚本(或 bash 或 Perl 脚本)并将输出传回 Java:
在 Java 中运行 Bash Shell 脚本
在 Java 中运行命令行
java Runtime.getruntime() 获取执行命令行程序的输出
解决方案 10:
您可以使用Java 本机接口从 Java 调用任何语言
解决方案 11:
这很好地概述了当前的选项。其中一些在其他答案中被提及。在他们决定不实现 Python 3 之前,Jython 不可用。许多其他项目来自 Python 方面,并希望访问 Java。但仍有几个选项,命名一些尚未命名的东西:gRPC
解决方案 12:
我有类似的要求,我认为对我来说最好的解决方案是thrift
(也是一个 rpc 解决方案),现在只需运行测试即可成功通过,并且可以使用thrift-generator从 java 接口生成 thrift 文件,然后从 thrift 文件生成 python 文件和 java 客户端文件
解决方案 13:
在从 Python 到 Java 的数据交换方面,我们可以将其作为休息服务并以 XML 或 Json 格式交换数据,但有时我们需要调用使用 Python 轻松创建的自动脚本以在 Java 文件中调用。