您好,登錄后才能下訂單哦!
這篇“Java中如何調(diào)用Python”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Java中如何調(diào)用Python”文章吧。
Python語(yǔ)言有豐富的系統(tǒng)管理、數(shù)據(jù)處理、統(tǒng)計(jì)類軟件包,因此從java應(yīng)用中調(diào)用Python代碼的需求很常見(jiàn)、實(shí)用。DataX 是阿里開(kāi)源的一個(gè)異構(gòu)數(shù)據(jù)源離線同步工具,致力于實(shí)現(xiàn)包括關(guān)系型數(shù)據(jù)庫(kù)(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各種異構(gòu)數(shù)據(jù)源之間穩(wěn)定高效的數(shù)據(jù)同步功能。Datax也是通過(guò)Java調(diào)用Python腳本。
Java提供了有兩種方法,分別為ProcessBuilder API和 JSR-223 Scripting Engine。
通過(guò)ProcessBuilder創(chuàng)建本地操作系統(tǒng)進(jìn)程啟動(dòng)python并執(zhí)行Python腳本, hello.py腳本簡(jiǎn)單輸出“Hello Python!”。需要開(kāi)發(fā)環(huán)境已經(jīng)安裝了python,并設(shè)置了環(huán)境變量。
@Test public void givenPythonScript_whenPythonProcessInvoked_thenSuccess() throws Exception { ProcessBuilder processBuilder = new ProcessBuilder("python", resolvePythonScriptPath("hello.py")); processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); List<String> results = readProcessOutput(process.getInputStream()); assertThat("Results should not be empty", results, is(not(empty()))); assertThat("Results should contain output of script: ", results, hasItem(containsString("Hello Python!"))); int exitCode = process.waitFor(); assertEquals("No errors should be detected", 0, exitCode); } private List<String> readProcessOutput(InputStream inputStream) throws IOException { try (BufferedReader output = new BufferedReader(new InputStreamReader(inputStream))) { return output.lines() .collect(Collectors.toList()); } } private String resolvePythonScriptPath(String filename) { File file = new File("src/test/resources/" + filename); return file.getAbsolutePath(); }
首先啟動(dòng)帶一個(gè)參數(shù)的python命令,參數(shù)為python腳本的絕對(duì)路徑??梢苑旁趈ava工程的resources目錄下。需要注意的是:redirectErrorStream(true),為了使得當(dāng)執(zhí)行腳本出現(xiàn)錯(cuò)誤時(shí),錯(cuò)誤輸出流被合并至標(biāo)準(zhǔn)輸出流。這樣設(shè)置可以從Process對(duì)象的getInputStream()方法中讀取錯(cuò)誤信息。如果沒(méi)有該設(shè)置,則需要分別用兩個(gè)方法獲取流:getInputStream() 和 getErrorStream() 。processBuilder.start()獲取Process對(duì)象,然后讀取輸出流并驗(yàn)證結(jié)果。
java6首次引入JSR-223規(guī)范,定義一組提供基本腳本功能的腳本API。這些API提供了執(zhí)行腳本和在Java和腳本語(yǔ)言之間共享值的機(jī)制。該規(guī)范主要目的是為了統(tǒng)一Java與不同實(shí)現(xiàn)JVM的動(dòng)態(tài)腳本語(yǔ)言的交互,Jython是在jvm上運(yùn)行python的java實(shí)現(xiàn)。假設(shè)我們?cè)贑LASSPATH上有Jython,框架自動(dòng)發(fā)現(xiàn)我們有可能使用該腳本引擎,并允許我們直接請(qǐng)求Python腳本引擎。因?yàn)镸aven有Jython,我們可以在maven中引用,當(dāng)然也下載直接安裝:
<dependency> <groupId>org.python</groupId> <artifactId>jython</artifactId> <version>2.7.2</version> </dependency>
可以通過(guò)下面代碼列出所有支持的腳本引擎:
public static void listEngines() { ScriptEngineManager manager = new ScriptEngineManager(); List<ScriptEngineFactory> engines = manager.getEngineFactories(); for (ScriptEngineFactory engine : engines) { LOGGER.info("Engine name: {}", engine.getEngineName()); LOGGER.info("Version: {}", engine.getEngineVersion()); LOGGER.info("Language: {}", engine.getLanguageName()); LOGGER.info("Short Names:"); for (String names : engine.getNames()) { LOGGER.info(names); } } }
如果Jython在環(huán)境中可用,應(yīng)該看到相應(yīng)的輸出:
...
Engine name: jython
Version: 2.7.2
Language: python
Short Names:
python
jython
現(xiàn)在使用Jython調(diào)用hello.py腳本:
@Test public void givenPythonScriptEngineIsAvailable_whenScriptInvoked_thenOutputDisplayed() throws Exception { StringWriter writer = new StringWriter(); ScriptContext context = new SimpleScriptContext(); context.setWriter(writer); ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("python"); engine.eval(new FileReader(resolvePythonScriptPath("hello.py")), context); assertEquals("Should contain script output: ", "Hello Python!", writer.toString().trim()); }
使用該API比上面的示例更簡(jiǎn)潔。首先設(shè)置ScriptContext包含StringWriter,用于保存執(zhí)行腳本的輸出。然后提供簡(jiǎn)稱讓ScriptEngineManager 查找腳本引擎,可以使用python或jython。最后驗(yàn)證輸出是否與期望一致。
其實(shí)也可以使用PythonInterpretor 類直接調(diào)用嵌入的python代碼:
@Test public void givenPythonInterpreter_whenPrintExecuted_thenOutputDisplayed() { try (PythonInterpreter pyInterp = new PythonInterpreter()) { StringWriter output = new StringWriter(); pyInterp.setOut(output); pyInterp.exec("print('Hello Python!')"); assertEquals("Should contain script output: ", "Hello Python!", output.toString().trim()); } }
使用PythonInterpreter類,可以通過(guò)exec方法直接執(zhí)行python代碼。和前面示例一樣通過(guò)StringWriter 捕獲執(zhí)行輸出。下面再看一個(gè)示例:
@Test public void givenPythonInterpreter_whenNumbersAdded_thenOutputDisplayed() { try (PythonInterpreter pyInterp = new PythonInterpreter()) { pyInterp.exec("x = 10+10"); PyObject x = pyInterp.get("x"); assertEquals("x: ", 20, x.asInt()); } }
上面示例可以使用get方法訪問(wèn)變量值。下面示例看如何捕獲錯(cuò)誤:
try (PythonInterpreter pyInterp = new PythonInterpreter()) { pyInterp.exec("import syds"); }
運(yùn)行上面代碼會(huì)拋出PyException 異常,與在本地執(zhí)行Python腳本輸出錯(cuò)誤一樣。
下面有幾點(diǎn)注意事項(xiàng):
PythonIntepreter 實(shí)現(xiàn)了AutoCloseable,最好與 try-with-resources 一起使用。
PythonIntepreter類名不是表示Python代碼的解析器,Python程序在Jython是運(yùn)行在jvm中,執(zhí)行前需要編譯為java字節(jié)碼。
盡管Jython是Java的Python實(shí)現(xiàn),但它可能不包含與本機(jī)Python相同的所有子包。
下面示例展示如何把java變量賦給Python變量:
import org.python.util.PythonInterpreter; import org.python.core.*; class test3{ public static void main(String a[]){ int number1 = 10; int number2 = 32; try (PythonInterpreter pyInterp = new PythonInterpreter()) { python.set("number1", new PyInteger(number1)); python.set("number2", new PyInteger(number2)); python.exec("number3 = number1+number2"); PyObject number3 = python.get("number3"); System.out.println("val : "+number3.toString()); } } }
以上就是關(guān)于“Java中如何調(diào)用Python”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。