1. 在java类中直接执行python语句
此方法需要引用 org.python包,需要下载Jpython。在这里先介绍一下Jpython。下面引入百科的解释: Jython是一种完整的语言,而不是一个Java翻译器或仅仅是一个Python编译器,它是一个Python语言在Java中的完全实现。Jython也有很多从CPython中继承的模块库。最有趣的事情是Jython不像CPython或其他任何高级语言,它提供了对其实现语言的一切存取。所以Jython不仅给你提供了Python的库,同时也提供了所有的Java类。这使其有一个巨大的资源库。 这里我建议下载最新版本的Jpython,因为可以使用的python函数库会比老版本的多些,目前最新版本为2.7.1。 下载jar包请点击Download Jython 2.7.1 - Standalone Jar 下载安装程序请点击Download Jython 2.7.1 - Installer 如果使用maven依赖添加的话,使用下面的语句
<!-- https://mvnrepository.com/artifact/org.python/jython-standalone --> <dependency> <groupId>org.python</groupId> <artifactId>jython-standalone</artifactId> <version>2.7.1</version> </dependency>以上准备好了,就可以直接在java类中写python语句了,具体代码如下:
PythonInterpreter interpreter = new PythonInterpreter(); interpreter.exec("a=[5,2,3,9,4,0]; "); interpreter.exec("print(sorted(a));"); //此处python语句是3.x版本的语法 interpreter.exec("print sorted(a);"); //此处是python语句是2.x版本的语法## 2. 在java中调用本地python脚本 首先在本地建立一个python脚本,命名为add.py,写了一个简单的两个数做加法的函数,代码如下:
def add(a,b): return a + bpython的功能函数已经写好,接下来我们写一个java的测试类(同样需要用到Jpython包),来测试一下是否可以运行成功。代码如下:
import org.python.core.PyFunction; import org.python.core.PyInteger; import org.python.core.PyObject; import org.python.util.PythonInterpreter; public class Java_Python_test { public static void main(String[] args) { // TODO Auto-generated method stub PythonInterpreter interpreter = new PythonInterpreter(); interpreter.execfile("D:\\add.py"); // 第一个参数为期望获得的函数(变量)的名字,第二个参数为期望返回的对象类型 PyFunction pyFunction = interpreter.get("add", PyFunction.class); int a = 5, b = 10; //调用函数,如果函数需要参数,在Java中必须先将参数转化为对应的“Python类型” PyObject pyobj = pyFunction.__call__(new PyInteger(a), new PyInteger(b)); System.out.println("the anwser is: " + pyobj); } }注意:以上两个方法虽然都可以调用python程序,但是使用Jpython调用的python库不是很多,如果你用以上两个方法调用,而python的程序中使用到第三方库,这时就会报错java ImportError: No module named xxx。遇到这种情况推荐使用下面的方法,即可解决该问题。
3. 使用Runtime.getRuntime()执行脚本文件(推荐) 本人觉得这种方法是最好的,并不需要引入相关的jar包,直接使用JDK自带的Runtime 下面我们来调一下强化学习的一个例子(相关的numpy和pandas第三方库自行去下载): 1.python强化学习代码 maze_env.py
import numpy as np import time import sys if sys.version_info.major == 2: import Tkinter as tk else: import tkinter as tk UNIT = 40 # pixels MAZE_H = 4 # grid height MAZE_W = 4 # grid width class Maze(tk.Tk, object): def __init__(self): super(Maze, self).__init__() self.action_space = ['u', 'd', 'l', 'r'] self.n_actions = len(self.action_space) self.title('maze') self.geometry('{0}x{1}'.format(MAZE_H * UNIT, MAZE_H * UNIT)) self._build_maze() def _build_maze(self): self.canvas = tk.Canvas(self, bg='white', height=MAZE_H * UNIT, width=MAZE_W * UNIT) # create grids for c in range(0, MAZE_W * UNIT, UNIT): x0, y0, x1, y1 = c, 0, c, MAZE_H * UNIT self.canvas.create_line(x0, y0, x1, y1) for r in range(0, MAZE_H * UNIT, UNIT): x0, y0, x1, y1 = 0, r, MAZE_W * UNIT, r self.canvas.create_line(x0, y0, x1, y1) # create origin origin = np.array([20, 20]) # hell hell1_center = origin + np.array([UNIT * 2, UNIT]) self.hell1 = self.canvas.create_rectangle( hell1_center[0] - 15, hell1_center[1] - 15, hell1_center[0] + 15, hell1_center[1] + 15, fill='black') # hell hell2_center = origin + np.array([UNIT, UNIT * 2]) self.hell2 = self.canvas.create_rectangle( hell2_center[0] - 15, hell2_center[1] - 15, hell2_center[0] + 15, hell2_center[1] + 15, fill='black') # create oval oval_center = origin + UNIT * 2 self.oval = self.canvas.create_oval( oval_center[0] - 15, oval_center[1] - 15, oval_center[0] + 15, oval_center[1] + 15, fill='yellow') # create red rect self.rect = self.canvas.create_rectangle( origin[0] - 15, origin[1] - 15, origin[0] + 15, origin[1] + 15, fill='red') # pack all self.canvas.pack() def reset(self): self.update() time.sleep(0.5) self.canvas.delete(self.rect) origin = np.array([20, 20]) self.rect = self.canvas.create_rectangle( origin[0] - 15, origin[1] - 15, origin[0] + 15, origin[1] + 15, fill='red') # return observation return self.canvas.coords(self.rect) def step(self, action): s = self.canvas.coords(self.rect) base_action = np.array([0, 0]) if action == 0: # up if s[1] > UNIT: base_action[1] -= UNIT elif action == 1: # down if s[1] < (MAZE_H - 1) * UNIT: base_action[1] += UNIT elif action == 2: # right if s[0] < (MAZE_W - 1) * UNIT: base_action[0] += UNIT elif action == 3: # left if s[0] > UNIT: base_action[0] -= UNIT self.canvas.move(self.rect, base_action[0], base_action[1]) # move agent s_ = self.canvas.coords(self.rect) # next state # reward function if s_ == self.canvas.coords(self.oval): reward = 1 done = True s_ = 'terminal' elif s_ in [self.canvas.coords(self.hell1), self.canvas.coords(self.hell2)]: reward = -1 done = True s_ = 'terminal' else: reward = 0 done = False return s_, reward, done def render(self): time.sleep(0.1) self.update()RL_brain.py
import numpy as np import pandas as pd class RL(object): def __init__(self, action_space, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9): self.actions = action_space # a list self.lr = learning_rate self.gamma = reward_decay self.epsilon = e_greedy self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64) def check_state_exist(self, state): if state not in self.q_table.index: # append new state to q table self.q_table = self.q_table.append( pd.Series( [0]*len(self.actions), index=self.q_table.columns, name=state, ) ) def choose_action(self, observation): self.check_state_exist(observation) # action selection if np.random.rand() < self.epsilon: # choose best action state_action = self.q_table.loc[observation, :] # some actions may have the same value, randomly choose on in these actions action = np.random.choice(state_action[state_action == np.max(state_action)].index) else: # choose random action action = np.random.choice(self.actions) return action def learn(self, *args): pass # off-policy class QLearningTable(RL): def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9): super(QLearningTable, self).__init__(actions, learning_rate, reward_decay, e_greedy) def learn(self, s, a, r, s_): self.check_state_exist(s_) q_predict = self.q_table.loc[s, a] if s_ != 'terminal': q_target = r + self.gamma * self.q_table.loc[s_, :].max() # next state is not terminal else: q_target = r # next state is terminal self.q_table.loc[s, a] += self.lr * (q_target - q_predict) # update # on-policy class SarsaTable(RL): def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9): super(SarsaTable, self).__init__(actions, learning_rate, reward_decay, e_greedy) def learn(self, s, a, r, s_, a_): self.check_state_exist(s_) q_predict = self.q_table.loc[s, a] if s_ != 'terminal': q_target = r + self.gamma * self.q_table.loc[s_, a_] # q_target基于选好的a_而不是Q(s_)的最大值 else: q_target = r self.q_table.loc[s, a] += self.lr * (q_target - q_predict) # 更新q_tablerun_this.py
from maze_env import Maze from RL_brain import SarsaTable def update(): for episode in range(100): # 初始化环境 observation = env.reset() # Sarsa根据state观测选择行为 action = RL.choose_action(str(observation)) while True: # 刷新环境 env.render() # 在环境中采取行为,获得下一个state_(observation_),reward,和终止信号 observation_, reward, done = env.step(action) # 根据下一个state(observation_)选取下一个action_ action_ = RL.choose_action(str(observation_)) #从(s, a, r, s, a)中学习,更新Q_table的参数 RL.learn(str(observation), action, reward, str(observation_), action_) # 将下一个的observation_和action_当成对应下一步的参数 observation = observation_ action = action_ if done: break # end of game print('game over') env.destroy() if __name__ == "__main__": env = Maze() RL = SarsaTable(actions=list(range(env.n_actions))) env.after(100, update) env.mainloop()下面是Runtime.getRuntime()调用python的Java代码:
@Test public void test() throws IOException { Process process = Runtime.getRuntime().exec("python d:\\Sarsa\\run_this.py"); }运行结果如下:
到此关于Java调python的方法就总结完毕了,本人强烈推荐第三种方法。
