Java 调用 python 的接口

    不管什么技术,不管什么问题,只要努力就能解决。

    最近在做项目的时候,需要java 调用 python 接口,在网上找了一些方法,但是总碰到一些问题,索性将网上的方法和自己的理解总结一下,希望对各位博友有所帮助,也请各位大神不吝赐教。

一:创建环境 Python 环境


import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;
/**
 * Jython环境,生存python解释器
 * @author webim
 *
 */
public final class JythonEnvironment
{
    private static JythonEnvironment INSTANCE = new JythonEnvironment();

    /**
     * 私有构造方法
     */
    private JythonEnvironment()
    {
    }

    /**
     * 获取单例
     * @return JythonEnvironment
     */
    public static JythonEnvironment getInstance()
    {
        return INSTANCE;
    }

    /**
     * 获取python系统状态,可根据需要指定classloader/sys.stdin/sys.stdout等
     * @return PySystemState
     */
    private PySystemState getPySystemState()
    {
        PySystemState.initialize();
        final PySystemState py = new PySystemState();
        py.setClassLoader(getClass().getClassLoader());
        return py;
    }

    /**
     * 获取python解释器
     * @return PythonInterpreter
     */
    public PythonInterpreter getPythonInterpreter(){
        PythonInterpreter inter = new PythonInterpreter(null, getPySystemState());
//        PythonInterpreter inter = new PythonInterpreter();
        return inter;
    }
    
    
}

 

二:调用 python 的接口

 

添加 JPython 依赖

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

上面这个依赖有问题,可用下面依赖避免各种问题。

        <dependency>
            <groupId>org.python</groupId>
            <artifactId>jython-standalone</artifactId>
            <version>2.7.0</version>
        </dependency>
因为 python 和 java是两种不同的语言,因此在项目的 controller 、service 和 mapper 中直接出现 Python 的接口,因此
自己封装  ExecPython   类,
封装python的接口,目的让 python 接口和java程序分隔开。

 

import org.python.core.PyFunction;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.Map;

/*enum的这个用法,可以作为变种的安全单例,值得借鉴哦 ^_^ */
@Service
@Component
public class ExecPython {

    public static final Logger logger = LoggerFactory.getLogger(Exception.class);

    //定义 python 解释器
    private static PythonInterpreter inter;

    public ExecPython() {
        this.inter  = JythonEnvironment.getInstance().getPythonInterpreter();
        this.inter.execfile("C:\\test.py");
    }

    //设置 python 脚本的路径
    public void setPythonPath (String pythonPath){
        this.inter.execfile(pythonPath);
    }



    public void execute(String scriptFile, Map<String,String> properties)
    {
        logger.info("获取解释器");
        try
        {

            PyFunction getNetInfo = (PyFunction) inter.get("getNetInfo", PyFunction.class);
            PyObject netInfo = getNetInfo.__call__();
            System.out.println("anwser = " + netInfo.toString());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            logger.info("Python 脚本文件执行失败");
        }
    }

    //获取 Python 字符串
    public String getString(){
//获取到python 脚本中的接口
        PyFunction func = (PyFunction) inter.get("adder", PyFunction.class);
        PyObject pyobj = func.__call__();
        System.out.println("anwser = " + pyobj.toString());
        return pyobj.toString();
    }
    // 获取当前数组
    public String getArr() {
        PyFunction getArr = (PyFunction) inter.get("getArr", PyFunction.class);
        PyObject pyobjTwo = getArr.__call__();
        pyobjTwo.__len__();
        System.out.println("anwser = " + pyobjTwo.toString()+" len:"+pyobjTwo.__len__());

        //将 PyObject 对象转换成 java  对象
        //Object object = pyobjTwo.__tojava__(List.class);
        //List<String> list = (List<String>) object;

        //将查询到数据转换成一个 JSON 字符串
        String result = pyobjTwo.toString();
        String JsonStr = "{" + result + "}";
        logger.info(JsonStr);
        logger.info("将查询的结果转换成 JSON 字符串:",JsonStr);

        return pyobjTwo.toString();
    }
}
 

三: python 脚本

 

def adder():    
   return "{'name':'leilei','age':'18'}"  
   
def getArr():
return ['aaa','bbb']


def getNetInfo():
return [{'DNS':'192.168.12.3','ip':'45.23.16.0'},{'DNS2':'192.168.12.2','ip2':'45.23.16.2'}]

 

问题:

2019-12-09 20:11:17.070 ERROR 4620 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'execPython' defined in file [D:\Lenovo\LenovoWorkspace\code\ip-modify\target\classes\cn\lenovo\ipmodify\service\ExecPython.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.lenovo.ipmodify.service.ExecPython]: Constructor threw exception; nested exception is ImportError: Cannot import site module and its dependencies: No module named site
Determine if the following attributes are correct:
  * sys.path: ['C:\\Users\\31307\\.m2\\repository\\org\\python\\jython\\2.7.0\\Lib', '__classpath__', '__pyclasspath__/']
    This attribute might be including the wrong directories, such as from CPython
  * sys.prefix: C:\Users\31307\.m2\repository\org\python\jython\2.7.0
    This attribute is set by the system property python.home, although it can
    be often automatically determined by the location of the Jython jar file

You can use the -S option or python.import.site=false to not import the site module

	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
	at cn.lenovo.ipmodify.IpmodifyApplication.main(IpmodifyApplication.java:13) [classes/:na]

 

主要是这句话:


You can use the -S option or python.import.site=false to not import the site module

可以使用-S选项或python.import.site=false不导入站点模块

像是设置 python 解释器的环境变量。

因此在创建解释器时,设置环境变量。

修改  JythonEnvironment 中的  getPythonInterpreter 函数

    public PythonInterpreter getPythonInterpreter(){

        Properties props = new Properties();
        props.put("python.home", "path to the Lib folder");
        props.put("python.console.encoding", "UTF-8");

        props.put("python.security.respectJavaAccessibility", "false");

        props.put("python.import.site", "false");

        Properties preprops = System.getProperties();
        PythonInterpreter.initialize(preprops,props,new String[0]);
        PythonInterpreter inter = new PythonInterpreter();
        return inter;
    }

 

 

 

  • 8
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值