从 Java 调用 python 函数的不同/更好的方法

Posted

技术标签:

【中文标题】从 Java 调用 python 函数的不同/更好的方法【英文标题】:Different / better approaches for calling python function from Java 【发布时间】:2017-01-17 12:45:37 【问题描述】:

我对python很陌生,正在尝试从java调用python的函数。

我的主要要求是:

调用应该是透明的,因为它不需要修改.py文件以使其能够从java中调用。我可能会得到任何包含一些函数的 python 文件。我应该能够调用这些函数中的任何一个,而无需修改 .py 文件。 我希望能够将两种原始类型(intStringfloats 等)或非原始类型(HashMapArrayList)的参数从 java 发送到 python 函数并接收将返回的对象(可能是原始类型或非原始类型)从 python 返回到 java。我也在使用 pandas DataFrame 和 numpy ndarray,因此也希望能够在 java 之间发送和接收相应的对象。 我最好想坚持使用 CPython 而不是 Jython,因为我可能需要使用 Jython 中可能不可用的较新库。

我在网上找到了几个选项。很少有:

使用 Jython 的 PythonInterpreter 可以调用 python 函数,而无需对 .py 脚本文件进行任何更改:

py1.py

 def square2(list):
     squares = []
     for i in list:
         squares.append(i*i)
     return squares

JythonTest.groovy

 import org.python.util.PythonInterpreter
 import org.python.core.*;

 class JythonTest
 
      static main(def args)
      
          PythonInterpreter pi = new PythonInterpreter()
          pi.exec("from py1 import square2")
          PyFunction pf = (PyFunction)pi.get("square2")
          println pf.__call__(new PyList([1,2,3,4]))[2]   //9
      
 

我能够很好地满足我的需求。但它不是 CPython。

使用ScriptEngine:这与 PythonInterpreter 非常相似。但反对它的 Jython。此外,与 PythonInterpreter 不同,我们不能使用 Jython 2.5+,也不能直接访问 PyObjects。所以这个选项可以很好的关闭。

使用py4j:找不到像 Jython PythonInterpreter 一样最小的示例 使用java2python。但是not much information is given关于从java调用python,这样我就可以断定我的上述要求是否可以满足。任何人都可以对此有所了解吗?更具体地说,如果我们可以编写与 Jython PythonInterpreter 中的代码一样少的代码。 使用JPype:但是在快速完成之后,我觉得我将无法像使用 Jython PythonInterpreter 那样编写最少的代码。我也觉得这个项目有点没有在开发中。是吗?

如果我正确理解了上述所有方法,那么 Jython PythonInterpreter 似乎是最佳选择。我在掌握它们时是否犯了错误?还有其他更好的选择吗?

【问题讨论】:

不完全相关,但有什么特别的原因让您更喜欢使用 CPython 而不是 Jython?在 Java 和 CPython 之间编组数据类型将变得更加困难,而构建在 JVM 互操作之上的 Jython 应该会更简单。 因为我觉得 Jython 会比 CPython 慢一点,也可能是因为我可能要等待一些 CPython 中可用但 Jython 尚未出现的新库 在我的用例中,Jython 的性能从未遇到过任何问题(当然,在您的用例中可能会有所不同)。库的可用性当然是一个潜在的问题,但是除非您确定需要使用 Jython 不可用的库,否则我认为使用它而不是 CPython 更容易。 (这是我通常做的,因为我不知道有任何胶水库可以实现您需要的互操作) 好吧,你和我一样认为 PythonInterpreter 是最好的选择? 在我看来,是的。 (除非如上所述,您绝对需要使用 CPython) 【参考方案1】:

@Mahesha999,关于坚持使用 CPython 的能力,从您上次的评论来看,这似乎很重要:

Jep 是一个不错的选择,它能够运行使用本地调用的 python 代码,比如你提到的 pandas。

您需要编写一些包装代码,因为 Jep 仅在最常用的类型之间实现 Java 和 Python 之间的自动转换,pandas.DataFrame 不是。

但是,如果您的用例并不复杂,您可以通过在数据帧实例上调用 DataFrame.values 来访问您的 pandas 对象作为 numpy.NDArray 对象,然后 Jep 实现到它为 NDArray 嵌入的 Java 类的转换。

您可以使用 Jep.getValue(String pythonVariableName, Class clazz) 从您执行的 Python 代码中返回 Java 值

例如

Jep jep = new Jep();
jep.eval("import my_script");
jep.eval("df = my_script.function_returning_a_dataframe()");
jep.eval("col = df.a_column.values");
NDArray myCol = jep.getValue("col", NDArray.class);

我在我用 Python 编写的一个项目中这样做,我需要将其作为插件集成到 Java 应用程序中,到目前为止它可以工作。

【讨论】:

【参考方案2】:

这个问题目前没有答案。使用 CPython 依赖于 Python 字节码的执行,这反过来又需要将 Python 解释器嵌入到执行环境中。由于没有 Java 运行时附带嵌入式 Python 解释器,因此 Jython 看起来确实是最好的答案。

有时您想要的答案不可用!

【讨论】:

我最近在重温这个。我意识到我错过了另一个选择:jep。有什么要寻找的吗?似乎有no simple way 可以使用jep 处理pandas 数据帧。此外,似乎我们无法使用 jep 获取从 python 到 java 的返回值。是这样吗?我在原始帖子中的要求也有所改变,因为我需要向/从 java 和 python 发送/接收 pandas 数据帧和 numpy ndarray。

以上是关于从 Java 调用 python 函数的不同/更好的方法的主要内容,如果未能解决你的问题,请参考以下文章

远程机器上的python模块

从 QMainWindow 调用具有变量名的 Python 函数

为啥我不能同时从 Java 执行不同的 Matlab 函数?

python调用java函数

寻求更好的 Python 3.x+ 方法在一个函数中构建多个不同的 HTML

从函数中退出以减少激活对象比递归或调用嵌套函数更好吗?