• 通过Java调用Python脚本


     

    在进行开发的过程中,偶尔会遇到需要使用Java调用Python脚本的时候,毕竟Python在诸如爬虫,以及科学计算等方面具有天然的优势。最近在工作中遇到需要在Java程序中调用已经写好的Python程序,故做一下记录。

    1常用的Java调用Python脚本的两种方式

    调用方式通常为以下两种:

    •通过Jython调用,即通过Jython.jar提供的类库实现

    •直接通过Java的Runtime实现,Runtime类的Runtime.getRuntime()开启进程,执行python脚本文件

    2通过Jython实现调用

    Jython简介

    Jython主页:http://www.jython.org/

    Jython是Python语言在Java平台的实现,本质上,Jython是由Java编写,其是在JVM上实现的Python语言。因此,可以直接通过Jython在Java中调用Python。

    Jython安装

    在安装Jython之前,必须确保本地已经安装了JDK。

    1. 通过Jython的官网下载对应版本的安装文件Installer和单独的standalone jar两个jar文件,放到特定的目录下,如C:jython2.7.0;

    2. 进入终端,切换到当前用于安装Jython的jar文件所在的目录下,执行java -jar jython_installer_2.7.0.jar,「当然也可以直接进入目录双击对应的jar文件进行安装」;

    3. 配置对应的环境变量,分别将对应的jar,lib目录加到CLASSPATH和Path中:

    –C:jython2.7.0jython.jar; 加入到CLASSPATH中

    –C:jython2.7.0;C:jython2.7.0Lib;加入到Path中

    此时在终端下执行jython命令,如果安装成功,则会进入到Jython的交互环境,可与Python的交互环境一样执行Python命令。同时也可以通过jython xxx.py命令执行python脚本文件。

    Jython执行Python脚本

    • 直接在Java中嵌入Python语句

    在Java中直接嵌入Python语句的用法较少,且实际意义不大。

    import org.python.util.PythonInterpreter;

    public class Main {

    public static void main(String[] args) {

    PythonInterpreter interpreter = new PythonInterpreter();

    //执行Python语句

    interpreter.exec("import sys");

    interpreter.exec("print 'hello'");

    interpreter.exec("print 2**100");

    }

    }

    • 在Java中执行已经编写好的名为xxx.py的 Python脚本

    直接通过Jython包调用写好的Python脚本,根据程序执行时的要求,大体可以分为以下几种情况:

    1.不需要通过Java程序向Python脚本中传递参数,也不需要获取Python脚本之行后的返回值,则可以通过文件流的方式直接打开脚本,并使用Jython的解释器执行。

    import org.python.util.PythonInterpreter;

    import java.io.*;

    public class Main {

    public static void main(String[] args) {

    PythonInterpreter interpreter = new PythonInterpreter();

    //执行Python脚本文件

    try {

    InputStream filepy = new FileInputStream("C:xxx.py");

    interpreter.execfile(filepy);

    filepy.close();

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    2.在Java中调用Python程序,同时需要传递参数和接收返回值。调用Python程序中的方法,可分为两种,一种是直接调用Python中写好的方法函数,另一种则是调用Python脚本的类中的函数。

    –直接调用函数,通过PyFunction实现参数的传递和返回值的获取

    import org.python.core.*;

    import org.python.util.PythonInterpreter;

    public class Main{

    public static void main(String[] args) {

    PythonInterpreter inter = new PythonInterpreter();

    //指定Python函数文件的路径

    String pythonFunc = "D:test.py";

    inter.execfile(pythonFunc);

    //获取函数名test

    PyFunction pyf = inter.get("test", PyFunction.class);

    //向函数中传递参数并获取返回结果

    PyObject res = pyf.__call__(Py.newInteger(2), Py.newInteger(3));

    System.out.print(res);

    inter.cleanup();

    inter.close();

    }

    }

    – 在Java中调用Python对象实例方法,使用PyObject方法实例化Python对象,调用Python对象方法,传递参数并切接收返回值。

    import org.python.core.*;

    import org.python.util.PythonInterpreter;

    public class Main{

    public static void main(String[] args) {

    PythonInterpreter inter = new PythonInterpreter();

    //python类路径

    String pythonClass = "D:test_class.py";

    //python 对象名

    String pythonObjName = "cal";

    // python类名

    String pythonClazzName = "Calculator";

    inter.execfile(pythonClass);

    //实例化Python对象

    inter.exec(PythonObjName + "=" + pythonClazzName + "()");

    //获取实例化的Python对象

    PyObject pyObject = inter.get(pythonObjName);

    //调用python对象方法,传递参数并接收返回值

    PyObject res = pyObject.invoke("power", new PyObject[] {Py.newInteger(2), Py.newInteger(3)});

    double power = Py.py2double(res);

    System.out.print(power);

    inter.cleanup();

    inter.close();

    }

    }

    其中,test_class.py文件的内容如下:

    import math

    class Calculator(object):

    def power(x, y):

    return math.pow(x, y)

    • 通过Runtime.getRuntime().exec()实现调用

    Runtime类是Java中一个与JVM运行时环境有关的类,通过Runtime.getRuntime()可以获取到当前JVM运行时的环境。Runtime上的大部分方法都是实例方法,即每次在进行运行时调用时都要用到getRuntime()方法。使用Runtime类执行Python脚本的方法非常简单粗暴,直接传入当前平台下的Python脚本执行命令即可。Java执行外部命令,主要方式还是使用Runtime类的exec()方法调用平台shell完成,如windows下的cmd,以及linux、unix、macOS下的的shell。

    通过Runtime执行Python脚本,可以直接通过命令向脚本中传递参数,并获取Python脚本的输出。

    public class Main{

    public static void main(String[] args) {

    String cmd = "python xxx.py argv1 argv2 ...";

    Process proc = Runtime.getRuntime().exec(cmd);

    InputStream is = proc.getInputStream();

    DataInputStream dis = new DataInputStream(is);

    String str = dis.readLine();

    proc.waitFor();

    System.out.println(str);

    }

    }

    3总结

    以上两种方法都可以实现在Java程序中调用Python脚本,但使用Jython进行调用时,效率较低,也会消耗较多资源,且调用的脚本需要Python的第三方依赖包时,需要在Jython中安装第三方包。而使用Runtime调用脚本时,更多的依赖于运行的平台,只要当前平台安装了对应的第三方依赖包,脚本就可以顺利执行,执行效率和直接执行Python脚本并没有区别。

    当然,在程序中不断的进行嵌套调用,会降低程序的执行效率,增加程序的耦合复杂度,不方便将来的扩展,因此并不建议大家经常使用,而可以考虑通过微服务的方法解决对应的问题。

    文章还有很多不足之处,希望大家多多交流,多多指教。

    参考链接

    1.五大基于JVM的脚本语言https://coolshell.cn/articles/2631.html

    2.Java调用Python http://tonl.iteye.com/blog/1918245

    3.Java Runtime.exec()的使用https://blog.csdn.net/toneylyx/article/details/52623597

    4.Why are there so many pythons https://www.oschina.net/translate/why-are-there-so-many-pythons

    5.Jython www.jython.org

  • 相关阅读:
    笨方法学python(本文为阅读时从此书摘录的笔记) 第一天
    关于C++中的虚拟继承的一些总结
    用提高效率的暴力法求3000以内的素数
    DAY 155 python中parse模块
    DAY 154 python自带的hmac模块
    DAY 153 Python中使用pymongo操作mongodb
    DAY 152 hmac模块
    DAY 151 parse模块
    DAY 150 setter&getter&@property
    DAY 149 property和setter装饰器
  • 原文地址:https://www.cnblogs.com/zhigu/p/10935182.html
Copyright © 2020-2023  润新知