先说句题外话:无论是在C中还是Java中调用Python,当遇到多线程的时候一定要想到GIL锁的存在。
在Python中调用C/C++代码:这也是最常见的混合编程方式。并且有很多优秀的开源项目可以帮助我们实现这种场景,比如pybind11.
在C/C++中调用Python代码:Python也为这种场景提供了丰富的接口。
Java中调用C/C++:也可以通过JNI实现Java与C/C++的相互调用。
那么Python和Java之间是否能够实现相互调用呢?
不难得到肯定的答案,至少可以通过Python->C/C++->Java的方式实现。
如果你了解Cython这个神器,就可以知道从Python到C是十分简单的。然后再到Java也就不是问题了。虽然想到了这个思路,但是为了更快的达到目的,试验之前还是在网上找了下,果然找到一篇十分不错的文章:
Python一键转Jar包,Java调用Python新姿势! - 掘金 (juejin.cn)
但在过程中还是遇到了一些细节问题,在这篇文章的基础上整理了下面的内容。
一、Java代码,文件名Test.java
这一块儿和文档中介绍的稍有不同。新建一个java工程,将这个文件加到里面去。
先把Java代码放上看起来有点本末倒置,但是后面会发现,在写接下来的C代码时会用到这个工程,来生成对应的C接口名。
package solution.src;
public class Test {
static {
System.load("/home/yourpath/python_C_Java/python/Test.cpython-36m-x86_64-linux-gnu.so");
}
public native void initModule();
public native void uninitModule();
public native String testFunction(String param);
public static void main(String[] args) {
Test tester = new Test();
tester.initModule();
String result = tester.testFunction("this is called from java");
tester.uninitModule();
System.out.println(result);
}
}
二、Python文件,取名JavaTest.pyx(pyx时cython代码的后缀,python是cython的一个子集,因此里面的代码完全可以写成python)
我们的目的就是让这些接口在Java中发挥它的作用,但这还不是在Java中直接调用的接口。这里照搬文章中的代码,但里面Python_API_TestFunction的函数名,之前是JNI_API_testFunction。在我的环境里面这个函数名字无论如何都找不到,后来自己写了个更简单的测试函数,测试成功。再后来又把我自己定义的函数删掉,改回JNI_API_testFunction又可以了,现在想应该是在网上拷贝代码时格式的问题。但这里还是用修改后的名字吧,因为JNI_这种格式在一些情况下是有固定含义的。总之运行时若提示找不到函数,则先怀疑一下Python代码本身是否有问题。
# FileName: Test.py
# 示例代码:将输入的字符串转变为大写
def logic(param):
print('this is a logic function')
print('param is [%s]' % param)
return param.upper()
# 接口函数,导出给Java Native的接口
def Python_API_TestFunction(param):
print("enter JNI_API_test_function")
result = logic(param)
print(result)
return res