在Java中调用Python

写在前面

在微服务架构大行其道的今天,对于将程序进行嵌套调用的做法其实并不可取,甚至显得有些愚蠢。当然,之所以要面对这个问题,或许是因为一些历史原因,或者仅仅是为了简单。恰好我在项目中就遇到了这个问题,需要在Java程序中调用Python程序。关于在Java中调用Python程序的实现,根据不同的用途可以使用多种不同的方法,在这里就将在Java中调用Python程序的方式做一个总结。

直接通过Runtime进行调用

我们知道,在Java中如果需要调用第三方程序,可以直接通过Runtime实现,这也是最直接最粗暴的做法。

public class InvokeByRuntime {/*** @param args* @throws IOException * @throws InterruptedException */public static void main(String[] args) throws IOExceptionInterruptedException {String exe = "python";String command = "D:\\calculator_simple.py";String num1 = "1";String num2 = "2";String[] cmdArr = new String[] {exe, command, num1, num2};Process process = Runtime.getRuntime().exec(cmdArr);InputStream is = process.getInputStream();DataInputStream dis = new DataInputStream(is);String str = dis.readLine();process.waitFor();System.out.println(str);}
}

输出:

3

calculator_simple.py:

# coding=utf-8
from sys import argvnum1 = argv[1]
num2 = argv[2]
sum = int(num1) + int(num2)
print sum

显然,在Java中通过Runtime调用Python程序与直接执行Python程序的效果是一样的,可以在Python中读取传递的参数,也可以在Java中读取到Python的执行结果。需要注意的是,不能在Python中通过return语句返回结果,只能将返回值写入到标准输出流中,然后在Java中通过标准输入流读取Python的输出值。

通过Jython调用

通过Jython调用Python?我在听到这个概念的时候一脸懵逼,不是说好的在Java中调用Python程序吗?这个Jython是什么鬼?难道是一个在Java中调用Python程序的组件或工具?其实,关于Jython是什么这个疑问,我估计有许多人在一开始接触的时候也是很疑惑的,下面我们就一一道来。

1. 什么是Jython

Jython主页:http://www.jython.org/currentdocs.html
按照官方的定义,Jython是Python语言在Java平台的实现。这个概念似乎有点拗口,反正我一开始并没有理解。Python难道不已经是一门语言了吗?什么叫做Jython是Python语言在Java平台的实现?
实际上,之所以存在这样的困惑主要是因为我们对Python语言的相关概念掌握和理解不清楚导致的。
Python其实只是一个语言规范,它存在多个不同语言实现的版本。具体来说,目前Python语言存在如下几个具体实现:
(1)CPython:CPython是标准Python,也是其他Python编译器的参考实现。通常提到“Python”一词,都是指CPython。CPython由C编写,将Python源码编译成CPython字节码,由虚拟机解释执行。没有用到JIT等技术,垃圾回收方面采用的是引用计数。
(2)Jython:Jython是在JVM上实现的Python,由Java编写。Jython将Python源码编译成JVM字节码,由JVM执行对应的字节码。因此能很好的与JVM集成,比如利用JVM的垃圾回收和JIT,直接导入并调用JVM上其他语言编写的库和函数。
(3)IronPython:IronPython与Jython类似,所不同的是IronPython在CLR上实现的Python,即面向.NET平台,由C#编写。IronPython将源码编译成TODO CLR,同样能很好的与.NET平台集成。即与Jython相同,可以利用.NET框架的JIT、垃圾回收等功能,能导入并调用.NET上其他语言编写的库和函数。IronPython默认使用Unicode字符串。
(4)PyPy:这里说的PyPy是指使用RPython实现,利用Tracing JIT技术实现的Python,而不是RPython工具链。PyPy可以选择多种垃圾回收方式,如标记清除、标记压缩、分代等。
(5)Pyston:Pyston由Dropbox开发,使用C++11编写,采用Method-at-a-time-JIT和Mark Sweep——Stop the World的GC技术。Pyston使用类似JavaScript V8那样的多层编译,其中也用到了LLVM来优化代码。

所以,我们现在再来理解什么是Jython就非常清楚了:Jython是Python语言规范在Java平台的具体实现。具体来说,可以将Python源码编译为JVM可以解释执行的字节码。
Jython原本叫做JPython,于1997年由Jim Hugunin创建,后来在1999年2.0版本发布的时候由Barry Warsaw更名为Jython,在这里我们就不再深究为什么要把JPython更名为Jython的原因了。注意: Jython从2.0版本开始就与CPython的版本保持一致,即:Jython 2.7与CPython 2.7保持对应。

虽然我们理解了什么是Jython,但是还存在一个疑问,为什么Python语言存在这么多不同语言的实现呢?为什么不能就只存在一个C语言实现的版本就可以了呢?存在这么多版本,真的给初学者带来了许多困惑。
当然,要回答这个问题可能就需要深究一些历史的原因了,就此打住。我们在此只讨论使用Jython能做什么以及如何使用Jython?

2. 使用Jython能做什么

既然Jython是Python语言在Java平台的实现,是Java语言实现的,那么是否可以在Jython程序中调用Java,在Java中也能调用Jython呢?
答案是肯定的,实际上,Jython的主要通途就是在Java中调用Python程序;而且,还可以直接在Jython程序中引用Java。

3. 如何使用Jython

3.1 安装Jython

在Jython的官方下载页面我们可以看到如下描述(详见:http://www.jython.org/downloads.html)

img

显然,可以下载2个Jython的jar包。其中,jython-installer-${version}.jar是用于安装Jython的,jython-standalone-${version}.jar用于嵌入到Java程序中使用。
什么意思?我一开始也是很疑惑,为什么要提供2个不同的jar包呢?他们有什么不同呢?2个不同的Jar包如何使用呢?
首先,jython-installer-${version}.jar用于安装Jython,就好比我们需要安装JRE,用于运行Java程序。除此之外,当需要在Python程序中引用一些公共的第三方库时,也需要先安装Jython才能下载所依赖的模块。

下载jython-installer-${version}.jar完毕之后,进入控制台,执行如下命令:

java -jar jython-installer-${version}.jar

此时会弹出一个图形化的安装界面,只需要一步一步选择相应参数进行安装即可。安装完毕之后,请将Jython安装目录添加为环境变量JYTHON_HOME,同时添加bin目录到PATH变量中:PATH=$PATH:$JYTHON_HOME/bin
进入控制台,执行如下命令就可以进入Jython的交互环境,这与CPython(我们通常说的Python)的命令行交互环境是一样的。

> jython
Jython 2.7.0 (default:9987c746f838, Apr 29 2015, 02:25:11)
[Java HotSpot(TM) 64-Bit Server VM (Oracle Corporation)] on java1.8.0_121
Type "help", "copyright", "credits" or "license" for more information.
>>> print("hello,world")
hello,world
>>>

当然,我们还可以使用jython命令运行一个Python程序。

> jython helloworld.py
hello,world

helloworld.py:

import sysprint("hello,world")

上面我们看到在Jython官网提供了2个Jar包,一个用于安装Jython,执行Python程序。那么,jython-standalone-${version}.jar又有什么用途呢?
实际上,当我们需要在Java中调用Python程序时,除了直接使用Java的Runtime调用,还可以直接使用Jython的API进行调用,而且通过Jython API可以直接调用Python程序中的指定函数或者对象方法,粒度更加精细。
当我们需要调用Jython的API时有两种方式:
第一,如果项目使用Maven进行构建,可以直接添加Jython的依赖配置到pom.xml文件中,如:

<dependency><groupId>org.python</groupId><artifactId>jython</artifactId><version>2.7.0</version>
</dependency>

第二,可以直接将jython-standalone-${version}.jar添加到项目classpath中,这样也可以调用Jython的相关API了。也就是说,jython-standalone-${version}.jar就是一个提供Jython API的jar独立jar包。

3.2 Java调用Python程序实践

Java通过Jython API调用Python程序,有几种用法:
(1)在Java中执行Python语句,相当于在Java中嵌入了Python程序,这种用法不常见,也没有太大的实际意义。

public static void main(String[] args) {System.setProperty("python.home""D:\\jython2.7.0");PythonInterpreter interp = new PythonInterpreter();// 执行Python程序语句interp.exec("import sys");interp.set("a"new PyInteger(42));interp.exec("print a");interp.exec("x = 2+2");PyObject x = interp.get("x");System.out.println("x: " + x);
}

输出:

42
x: 4

(2)在Java中简单调用Python程序,不需要传递参数,也不需要获取返回值。

public static void main(String[] args) throws IOException {System.setProperty("python.home""D:\\jython2.7.0");String python = "D:\\simple_python.py";PythonInterpreter interp = new PythonInterpreter();interp.execfile(python);interp.cleanup();interp.close();
}

simple_python.py:

# coding=utf-8
print("Do simple thing in Python")
print("输出中文")

(3)在Java中单向调用Python程序中的方法,需要传递参数,并接收返回值。Python既支持面向函数式编程,也支持面向对象编程。因此,调用Python程序中的方法也分别以面向函数式编程和面向对象式编程进行说明。

public static void main(String[] args) throws IOException {System.setProperty("python.home""D:\\jython2.7.0");// 1. Python面向函数式编程: 在Java中调用Python函数String pythonFunc = "D:\\calculator_func.py";PythonInterpreter pi1 = new PythonInterpreter();// 加载python程序pi1.execfile(pythonFunc);// 调用Python程序中的函数PyFunction pyf = pi1.get("power", PyFunction.class);PyObject dddRes = pyf.__call__(Py.newInteger(2), Py.newInteger(3));System.out.println(dddRes);pi1.cleanup();pi1.close();// 2. 面向对象式编程: 在Java中调用Python对象实例的方法String pythonClass = "D:\\calculator_clazz.py";// python对象名String pythonObjName = "cal";// python类名String pythonClazzName = "Calculator";PythonInterpreter pi2 = new PythonInterpreter();// 加载python程序pi2.execfile(pythonClass);// 实例化python对象pi2.exec(pythonObjName + "=" + pythonClazzName + "()");// 获取实例化的python对象PyObject pyObj = pi2.get(pythonObjName);// 调用python对象方法,传递参数并接收返回值PyObject result = pyObj.invoke("power", new PyObject[] {Py.newInteger(2), Py.newInteger(3)}); double power = Py.py2double(result);System.out.println(power);pi2.cleanup();pi2.close();
}

输出:

8.0
8.0

calculator_func.py:

# coding=utf-8
import math# 面向函数式编程
def power(x, y):return math.pow(x, y)

calculator_clazz.py:

# coding=utf-8
import math# 面向对象编程
class Calculator(object):# 计算x的y次方def power(self, x, y):return math.pow(x,y)

(4)高级调用,也是在Java中调用Python程序最常见的用法:Python程序可以实现Java接口,在Python中也可以调用Java方法。

public static void main(String[] args) throws IOException {System.setProperty("python.home""D:\\jython2.7.0");// Python程序路径String python = "D:\\python\\fruit_controller.py";// Python实例对象名String pyObjName = "pyController";// Python类名String pyClazzName = "FruitController";Fruit apple = new Apple();Fruit orange = new Orange();PythonInterpreter interpreter = new PythonInterpreter();// 如果在Python程序中引用了第三方库,需要将这些被引用的第三方库所在路径添加到系统环境变量中// 否则,在执行Python程序时将会报错: ImportError: No module named xxxPySystemState sys = interpreter.getSystemState();sys.path.add("D:\\python");// 加载Python程序interpreter.execfile(python);// 实例 Python对象interpreter.exec(pyObjName + "=" + pyClazzName + "()");// 1.在Java中获取Python对象,并将Python对象转换为Java对象// 为什么能够转换? 因为Python类实现了Java接口,通过转换后的Java对象只能调用接口中定义的方法GroovyController controller = (GroovyController) interpreter.get(pyObjName).__tojava__(GroovyController.class);controller.controllFruit(apple);controller.controllFruit(orange);// 2.在Java直接通过Python对象调用其方法// 既可以调用实现的Java接口方法,也可以调用Python类自定义的方法PyObject pyObject =	interpreter.get(pyObjName);pyObject.invoke("controllFruit", Py.java2py(apple));pyObject.invoke("controllFruit", Py.java2py(orange));pyObject.invoke("printFruit", Py.java2py(apple));pyObject.invoke("printFruit", Py.java2py(orange));// 3.在Java中获取Python类进行实例化对象: 没有事先创建 Python对象PyObject pyClass = interpreter.get("FruitController");PyObject pyObj = pyClass.__call__();pyObj.invoke("controllFruit", Py.java2py(apple));pyObj.invoke("controllFruit", Py.java2py(orange));PyObject power = pyObj.invoke("power", new PyObject[] {Py.newInteger(2), Py.newInteger(3)});if(power != null) {double p = Py.py2double(power);System.out.println(p);}interpreter.cleanup();interpreter.close();
}

输出:

Show: I am a java apple.
controllFruit Python Apple
controllFruit END
Show: I am a java orange.
controllFruit Python Orange
controllFruit END
Show: I am a java apple.
controllFruit Python Apple
controllFruit END
Show: I am a java orange.
controllFruit Python Orange
controllFruit END
Show: I am a java apple.
printFruit Python Apple
printFruit END
Show: I am a java orange.
printFruit Python Orange
printFruit END
Show: I am a java apple.
controllFruit Python Apple
controllFruit END
Show: I am a java orange.
controllFruit Python Orange
controllFruit END
8.0

fruit_controller.py:

# coding=utf-8from calculator_clazz import Calculator
from java.lang import String
from org.test.inter import GroovyController
from org.test.inter import Fruit# 在Python中实现Java接口: org.test.inter.GroovyController
class FruitController(GroovyController):# 实现接口方法def controllFruit(self, fruit):# 在Python中调用Java对象方法fruit.show()if(fruit.getType() == "apple"):print ("controllFruit Python Apple")if(fruit.getType() == "orange"):print ("controllFruit Python Orange")print ("controllFruit END")# 自定义新方法    def printFruit(self, fruit):fruit.show()if(fruit.getType() == "apple"):print ("printFruit Python Apple")if(fruit.getType() == "orange"):print ("printFruit Python Orange")print ("printFruit END")# 引用第三方python程序def power(self, x, y):cal = Calculator()return cal.power(x, y)

Java接口和实现类:

// 该接口用于在Python中实现
public interface GroovyController {public void controllFruit(Fruit fruit);
}// 在Java中使用的接口
public interface Fruit {public String getName();public String getType();public void show();
}// Apple
public class Apple implements Fruit {public String getName() {return "java apple";}public String getType() {return "apple";}public void show() {System.out.println("Show: I am a java apple.");}
}// Orange
public class Orange implements Fruit {public String getName() {return "ava orange";}public String getType() {return "orange";}public void show() {System.out.println("Show: I am a java orange.");}

另外,对于在eclipse中运行时控制台报错:

Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0

请添加VM参数:-Dpython.console.encoding=UTF-8,详见:jython在eclipse控制台出现Failed to install ‘’: java.nio.charset.UnsupportedCharsetException: cp0解决方法_北一-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/554864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android 导航动画,安利一个Android导航库

SlidingRootNav这是一个像DrawerLayout一样的抽屉式的导航库&#xff0c;这个库实现的抽屉在content view的下层&#xff0c;滑动之后&#xff0c;才能看到相应的导航页使用Gradle添加依赖compile com.yarolegovich:sliding-root-nav:1.0.2使用说明创建一个 content_view.xml或…

android 界面组件,安卓开发学习周第三篇——Android中的UI组件

原标题&#xff1a;安卓开发学习周第三篇——Android中的UI组件在Android APP中&#xff0c;所有的用户界面元素都是由View和ViewGroup的对象构成的。View是绘制在屏幕上的用户能与之交互的一个对象。而ViewGroup则是一个用于存放其他View(和ViewGroup)对象的布局容器&#xff…

BigDecimal.ZERO替代new BigDecimal(0)

这里只是想分享下&#xff0c;平时如果我们想要定义一些BigDecimal类型的变量&#xff0c;可以先看看BigDecimal有没有已经先做了定义&#xff0c;如new BigDecimal(0)就可以用BigDecimal.ZERO来代替&#xff0c;如下&#xff1a; BigDecimal bigDecimal BigDecimal.ZERO;描述…

用js拼html写下拉框,js实现下拉框效果(select)

效果图&#xff1a;代码如下&#xff1a;*{padding: 0;margin:0;}ul,li{list-style: none}.left{float: left;}.right{float: right;}.select_contain{font-size: 14px;color: #333;line-height: 38px;margin: 30px 0;}.select_item{margin-right: 50px;position: relative;}.s…

Gson Builder — 基础 命名策略

文章目录Gson Builder — 基础& 命名策略GsonBuilder 基础命名策略字段命名策略 - IDENTITY字段命名策略 - LOWER_CASE_WITH_UNDERSCORES字段命名策略 - LOWER_CASE_WITH_DASHES字段命名策略 - UPPER_CAMEL_CASE字段命名策略 - UPPER_CAMEL_CASE_WITH_SPACESSerializedName…

keil html转换工具,网页转换工具FCARM和makefsfile的使用简介

网页转换工具FCARM和makefsfile的使用简介[复制链接]首先在这里要提一下Keil的网页转换工具FCARM.exe的使用&#xff0c;花费了我好几个小时。TI也有一个类似的程序&#xff0c;是Makefsfile&#xff0c;并且源码公开的。1.gif (31.45 KB, 下载次数: 0)2010-11-8 16:44 上传2.j…

Google Gson用法详解

文章目录一、简介二、依赖三、基本用法1、创建Gson实例1.1、new Gson()1.2、GsonBuilder.build()2、Java对象–>JSON3、JSON–>Java对象4、漂亮地输出5、JSON array --> Java array/list5.1 、 JSON array -->Java对象5.2 、JSON array–>List5.3 、JSON array–…

Socket通信原理

Socket通信原理 一、Socket的定义 1、Socket是一个网络通信的套接字&#xff08;接口&#xff09; 二、Socket的实现流程 1、Socket在客户端和服务端发生了什么&#xff1f; 服务器&#xff1a; a.socket()创建socket对象 b.bind()为socket对象绑定协议&#xff0c;赋予名…

CRC校验原理及步骤

1、CRC是用来干嘛的&#xff1f; 检测数据传输过程中是否出现错误&#xff08;某些位&#xff0c;或某几位&#xff0c;或者某块区域位错误&#xff09;。 2、CRC是否能校正数据传输中的错误&#xff1f; CRC只能检错&#xff0c;不能纠错。如果发现错误&#xff0c;可根据双…

在组策略中用户策略仅对特定计算机生效,将组策略应用到满足条件的计算机---配置组策略筛选...

配置组策略筛选Microsoft?Windows?Management Instrumentation (WMI) 大概是我们已知的 Microsoft 保存最好的秘密。尽管如此&#xff0c;但毫无疑问&#xff0c;WMI 是 Microsoft 主要的针对 Windows 的管理支持技术。在Windows Server 2008的组策略高级管理中&#xff0c;对…

Idea 类和包的路径后面出现100%methods;84% lines coveredIdea coverage覆盖率测试工具的使用

Idea 类和包的路径后面出现100%methods;84% lines covered 其他先不说&#xff0c;先看一下出现的问题&#xff1a; 类和包的路径后面多了100%methods;84% lines covered&#xff0c;以前类路径后面是什么都没的&#xff1b; 长话短说&#xff1b; 产生原因&#xff1a; 因…

SpringBoot:整合监听器/过滤器和拦截器

整合监听器/过滤器和拦截器 在实际开发过程中&#xff0c;经常会碰见一些比如系统启动初始化信息、统计在线人数、在线用户数、过滤敏/高词汇、访问权限控制(URL级别)等业务需求。实现以上的功能&#xff0c;都会或多或少的用到过滤器、监听器、拦截器。 一.SpringBoot整合过…

全国计算机英语四六级准考证打印准考证号,2017全国大学生英语四六级准考证打印...

2017年上半年度CET考试时间为6月17日&#xff0c;同学们打印准考证了吗?为方便大家打印四六级准考证&#xff0c;yjbys小编为大家分享英语四级考试准考证打印官方主页入口如下&#xff1a;2017年上半年度CET考试时间及报名方式一、考试科目及时间1.笔试考试时间日期(6月17日)考…

Centos7配置Jenkins

Centos7配置Jenkins jenkins 官方下载地址&#xff1a;https://mirrors.jenkins-ci.org/redhat/ maven 官方下载地址&#xff1a;https://archive.apache.org/dist/maven/maven-3/ tomcat 官方下载地址&#xff1a;https://tomcat.apache.org/download-90.cgi 1、配置jdk …

计算机硬盘用u盘维修,U盘装机大师修复磁盘坏道详细教程

我们都知道当我们的磁盘使用的时间久了就会容易出现各种问题&#xff0c;然而硬盘的坏道是最常见的问题之一。关于磁盘出现坏道有很多原因&#xff0c;诸如硬盘本身质量问题&#xff0c;老化&#xff0c;使用不当等等。我们的硬盘内存太小也会导致应用软件对硬盘频繁访问&#…

多屏幕炒股计算机配置,多屏幕股票交易计算机配置建议使用i59400F计算机主机配置(最多六个屏幕)...

在经历了几年的熊市股市之后&#xff0c;2019年股市似乎有所回升. 最近&#xff0c;许多用户询问多屏股票交易计算机的配置&#xff0c;例如三屏&#xff0c;四屏&#xff0c;和六屏. 实际上&#xff0c;与普通计算机的最大区别是该图形卡需要配备多屏幕图形卡. 一台计算机可以…

小学二年级上学期计算机教案,小学数学二年级上册分苹果教案设计

小学数学二年级上册分苹果教案设计〖教学目标1.经历分苹果等实际操作&#xff0c;初步体会有余数除法与生活的密切联系&#xff0c;进一步体会除法的意义。2.通过实际操作&#xff0c;抽象出有余数除法的书写格式&#xff0c;并体会余数一定要比除数小。〖教材分析分苹果是二年…

生物计算机的主要原材料是(),新材料为生物计算机打造“神经元”和“突触”...

一项最新研究利用复杂的氧化物&#xff0c;打造出了与神经元和突触相似的元件。图片来自pixabay.com虽然电脑的计算速度比人脑快&#xff0c;但在物体识别任务等方面&#xff0c;人脑还是更胜一筹。除此之外&#xff0c;人脑耗费的能量也远低于电脑。大脑的运作方式可以在一定程…

hotmail接收邮件服务器(pop),Microsoft微软邮箱 outlook、hotmail 打开pop和imap的方法

分享个微软邮箱 outlook、hotmail 打开pop和imap的方法只有打开了pop或者imap &#xff0c; foxmail一类的邮件管理客户端才能正常收邮件&#xff1b;打开了smtp才能正常发邮件。设置方法如图&#xff1a;1.登录进去账户以后&#xff0c;点击右上角的设置&#xff0c;齿轮图标&…

MySQL 索引 是如何提高 查询效率 的?

前言 我们都知道当查询数据库变慢时&#xff0c;需要建索引去优化。但是只知道索引能优化显然是不够的&#xff0c;我们更应该知道索引的原理&#xff0c;因为不是加了索引就一定会提升性能。那么接下来就一起探索MYSQL索引的原理吧 什么是索引 索引其实是一种能高效帮助MYS…