標籤:ror imp 需要 java代碼 list trace ted 通過 詳細
有時候,我們會碰到這樣的問題:與A同學合作寫代碼,A同學只會寫Python,而不會Java,
而你只會寫Java並不擅長Python,並且發現難以用Java來重寫對方的代碼,這時,就不得不想方設法“調用對方的代碼”。
下面我將舉一些簡單的小例子,藉此說明:如何在Java中調用Python代碼。
看懂這篇文章只需要具備:
主要內容如下:
- 什麼是Jython?
- 一個HelloPython程式
- 在Jvm中執行Python指令碼
- 僅在Java中調用Python編寫的函數
- 包含第三方模組的情況:一個手寫辨識程式
什麼是Jython?
Jython(原JPython),是一個用Java語言寫的Python解譯器。
在沒有第三方模組的情況下,通常選擇利用Jython來調用Python代碼,它是一個開源的JAR包。
你可以選擇到官網下載,如果訪問不了,請點擊這裡。
一個HelloPython程式
import org.python.util.PythonInterpreter;public class HelloPython { public static void main(String[] args) { PythonInterpreter interpreter = new PythonInterpreter(); interpreter.exec("print(‘hello‘)"); }}
什麼是PythonInterpreter?它的中文意思即是“Python解譯器”。我們知道Python程式都是通過解譯器來執行的,我們在Java中建立一個“解譯器”對象,類比Python解譯器的行為,通過exec("Python語句")直接在JVM中執行Python代碼,上面代碼的輸出結果為:hello
在Jvm中執行Python指令碼
interpreter.execfile("D:/labs/mytest/hello.py");
如上,將exec改為execfile就可以了。需要注意的是,這個.py檔案不能含有第三方模組,因為這個“Python指令碼”最終還是在JVM環境下執行的,如果有第三方模組將會報錯:java ImportError: No module named xxx
僅在Java中調用Python編寫的函數
先完成一個hello.py代碼:
def hello(): return ‘Hello‘
在Java代碼中調用這個函數:
import org.python.core.PyFunction;import org.python.core.PyObject;import org.python.util.PythonInterpreter;public class HelloPython { public static void main(String[] args) { PythonInterpreter interpreter = new PythonInterpreter(); interpreter.execfile("D:/labs/hello.py"); PyFunction pyFunction = interpreter.get("hello", PyFunction.class); // 第一個參數為期望獲得的函數(變數)的名字,第二個參數為期望返回的物件類型 PyObject pyObject = pyFunction.__call__(); // 調用函數 System.out.println(pyObject); }}
上面的代碼執行結果為:Hello
即便只是調用一個函數,也必須先載入這個.py檔案,之後再通過Jython包中所定義的類擷取、調用這個函數。
如果函數需要參數,在Java中必須先將參數轉化為對應的“Python類型”,例如:
__call__(new PyInteger(a), new PyInteger(b))
a,b的類型為Java中的int型,還有諸如:PyString(String string)、PyList(Iterator<PyObject> iter) 等。
詳細可以參考官方的api文檔。
包含第三方模組的情況:一個手寫辨識程式
這是我和舍友合作寫的一個小程式,完整代碼在這裡:http://pan.baidu.com/s/1sl4l68H ,介面上引用了core java上的一段代碼。
因為在Python程式中使用了第三方的NumPy模組,導致無法通過Jython執行,又由於個人水平的限制無法完全用Java重寫,不得不出此下策。下面純粹是個人思路,沒有深入查資料。思路大概是:僅僅是通過Java執行一個本地程式(未必是.Py),然後通過一個本地檔案做資料互動。
核心代碼如下:
import java.io.*;class PyCaller { private static final String DATA_SWAP = "temp.txt"; private static final String PY_URL = System.getProperty("user.dir") + "\\test.py"; public static void writeImagePath(String path) { PrintWriter pw = null; try { pw = new PrintWriter(new FileWriter(new File(DATA_SWAP))); } catch (IOException e) { e.printStackTrace(); } pw.print(path); pw.close(); } public static String readAnswer() { BufferedReader br; String answer = null; try { br = new BufferedReader(new FileReader(new File(DATA_SWAP))); answer = br.readLine(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return answer; } public static void execPy() { Process proc = null; try { System.out.println(System.getProperty("user.dir") + "\\test.py"); proc = Runtime.getRuntime().exec("python " + PY_URL); proc.waitFor(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } // 測試碼 public static void main(String[] args) throws IOException, InterruptedException { writeImagePath("D:\\labs\\mytest\\test.jpg"); execPy(); System.out.println(readAnswer()); }}
實際上就是通過Java執行一個命令列指令。
如何在Java中調用Python代碼