Hogyan hívhatunk Python-ot Java-ról
1. Áttekintés
A Python egyre népszerűbb programozási nyelv, különösen a tudományos közösségben a numerikus és statisztikai csomagok gazdag változatossága miatt. Ezért nem szokatlan követelmény a Python-kód meghívása a Java-alkalmazásainkból.
Ebben az oktatóanyagban megnézzük a Python kód Java-ból történő hívásának néhány leggyakoribb módját.
2. Egyszerű Python szkript
A bemutató során egy nagyon egyszerű Python szkriptet fogunk használni, amelyet egy dedikált fájlban definiálunk hello.py:
nyomtatás ("Hello Baeldung olvasók !!")
Ha feltételezzük, hogy működik egy Python telepítés, akkor a szkript futtatásakor látni kell az üzenetet:
$ python hello.py Helló Baeldung olvasók !!
3. Core Java
Ebben a szakaszban két különböző lehetőséget veszünk szemügyre, amelyek segítségével a Java Java segítségével meghívhatjuk a Python szkriptünket.
3.1. Használata ProcessBuilder
Először vessünk egy pillantást arra, hogyan használhatjuk a ProcessBuilder API egy natív operációs rendszer elindításához piton és hajtsa végre egyszerű szkriptünket:
@Test public void givenPythonScript_whenPythonProcessInvoked_thenSuccess () dobja a Kivételt {ProcessBuilder processBuilder = new ProcessBuilder ("python", ResolPythonScriptPath ("hello.py")); processBuilder.redirectErrorStream (true); Process process = processBuilder.start (); Eredmények felsorolása = readProcessOutput (process.getInputStream ()); assertThat ("Az eredmények nem lehetnek üresek", az eredmények (nem (üres ()))); assertThat ("Az eredményeknek tartalmazniuk kell a szkript kimenetét:", results, hasItem (tartalmazString ("Helló Baeldung olvasók !!"))); int exitCode = process.waitFor (); assertEquals ("Nem szabad hibát észlelni", 0, exitCode); }
Ebben az első példában a piton parancsot egy argumentummal, amely a mi abszolút utunk hello.py forgatókönyv. Megtalálhatjuk a mi teszt / források mappába.
Összefoglalva: létrehozzuk a sajátunkat ProcessBuilder objektum átadja a parancsot és az argumentum értékeket a konstruktornak. Fontos megemlíteni a hívást is redirectErrorStream (true). Bármilyen hiba esetén a hiba kimenet összeolvad a standard kimenettel.
Ez hasznos, mivel azt jelenti, hogy a megfelelő kimenetről bármilyen hibaüzenetet kiolvashatunk, amikor meghívjuk a getInputStream () módszer a Folyamat tárgy. Ha nem állítjuk be ezt a tulajdonságot igaz, akkor le kell olvasnunk két különálló adatfolyam kimenetét a getInputStream () és a getErrorStream () mód.
Most elindítjuk a folyamatot a Rajt() módszer a Folyamat tárgy. Ezután elolvassuk a folyamat kimenetét, és ellenőrizzük, hogy a tartalom elvárható-e.
Mint korábban említettük, feltételeztük, hogy a piton parancs a PÁLYA változó.
3.2. Munka a JSR-223 parancsfájlmotorral
A JSR-223, amelyet először a Java 6-ban vezettek be, meghatározza a parancsfájlok alapfunkcióit biztosító szkript API-k készletét. Ezek a módszerek biztosítják a parancsfájlok végrehajtásának mechanizmusait, valamint az értékek megosztását a Java és a szkriptnyelv között. A szabvány fő célja az volt, hogy megpróbáljon valamilyen egységességet teremteni a Java különböző szkriptnyelveivel való együttműködésben.
Bármely dinamikus nyelvhez használhatjuk a beépíthető szkriptmotor-architektúrát, feltéve, hogy természetesen rendelkezik JVM-implementációval. A Jython a Python Java platform implementációja, amely a JVM-en fut.
Feltéve, hogy a Jython van a CLASSPATH, a keretrendszernek automatikusan fel kell fedeznie, hogy lehetőségünk van ennek a szkriptmotornak a használatára, és lehetővé kell tennie, hogy közvetlenül a Python szkriptmotort kérjük.
Mivel a Jython elérhető a Maven Central-tól, egyszerűen felvehetjük a mi pom.xml:
org.python jython 2.7.2
Hasonlóképpen, közvetlenül is letölthető és telepíthető.
Soroljuk fel az összes rendelkezésünkre álló szkriptmotort:
ScriptEngineManagerUtils.listEngines ();
Ha lehetőségünk van a Jython használatára, meg kell jelenítenünk a megfelelő parancsfájlmotort:
... A motor neve: jython Verzió: 2.7.2 Nyelv: python Rövid nevek: python jython
Most, hogy tudjuk, hogy használhatjuk a Jython parancsfájlmotort, menjünk előre, és nézzük meg, hogyan hívhatjuk a sajátunkat hello.py forgatókönyv:
@Test public void givenPythonScriptEngineIsAvailable_whenScriptInvoked_thenOutputDisplayed () dobja a Kivételt {StringWriter író = új StringWriter (); ScriptContext context = új SimpleScriptContext (); context.setWriter (író); ScriptEngineManager manager = új ScriptEngineManager (); ScriptEngine motor = manager.getEngineByName ("python"); engine.eval (új FileReader (resolutionPythonScriptPath ("hello.py")), kontextus); assertEquals ("Szkript kimenetet kell tartalmaznia:", "Helló Baeldung olvasók !!", író.toString (). trim ()); }
Mint láthatjuk, nagyon egyszerű ezzel az API-val dolgozni. Először az a ScriptContext amely tartalmazza a StringWriter. Ezt fogjuk használni a meghívni kívánt szkript kimenetének tárolására.
Ezután használjuk a getEngineByName módszere ScriptEngineManager osztályban felkutatni és létrehozni a ScriptEngine adott rövid névre. Esetünkben átmehetünk piton vagy jython amelyek a motorhoz társított két rövid név.
Az előző lépéshez hasonlóan az utolsó lépés az, hogy megszerezzük a szkript kimenetét, és ellenőrizzük, hogy az megfelel-e annak, amire számítottunk.
4. Jython
A Jython folytatásával lehetőségünk van Python kód beágyazására is közvetlenül a Java kódunkba. Ezt megtehetjük a PythonInterpretor osztály:
@Test public void givenPythonInterpreter_whenPrintExecuted_thenOutputDisplayed () {try (PythonInterpreter pyInterp = new PythonInterpreter ()) {StringWriter output = new StringWriter (); pyInterp.setOut (output); pyInterp.exec ("print ('Helló Baeldung olvasók !!')"); assertEquals ("Tartalmaznia kell a szkript kimenetét:", "Helló Baeldung olvasók !!", output.toString () .trim ()); }}
Használni a PythonInterpreter osztály lehetővé teszi számunkra a Python forráskód sztring végrehajtását a exec módszer. Mint korábban, a StringWriter hogy megragadja a végrehajtás kimenetét.
Most nézzünk meg egy példát, ahol két számot adunk össze:
@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 ()); }}
Ebben a példában láthatjuk, hogyan használhatjuk a kap metódus segítségével elérheti a változó értékét.
Utolsó Jython példánkban meglátjuk, mi történik, ha hiba lép fel:
try (PythonInterpreter pyInterp = új PythonInterpreter ()) {pyInterp.exec ("sydd importálása"); }
Amikor ezt a kódot futtatjuk a PyException dobásra kerül, és ugyanazt a hibát fogjuk látni, mintha natív Python-nal dolgoznánk:
Traceback (a legutóbbi hívás utoljára): "" fájl, 1. sor, az ImportError fájlban: Nincs syds nevű modul
Néhány pontot meg kell jegyeznünk:
- Mint PythonIntepreter megvalósítja Automatikusan zárható, jó gyakorlat használni erőforrásokkal próbálkozzon amikor ezzel az osztállyal dolgozik
- A PythonInterpreter Az osztály neve nem jelenti azt, hogy a Python kódunkat értelmezzük. A Jythonban található Python programokat a JVM futtatja, ezért a végrehajtás előtt Java bytecode-ba fordítják
- Bár a Jython a Java Python-implementációja, előfordulhat, hogy nem tartalmazza az összes olyan alcsomagot, mint a natív Python
5. Apache Commons Exec
Egy másik harmadik fél könyvtár, amelynek használatát fontolóra vehetjük, az Apache Common Exec, amely megpróbálja kiküszöbölni a Java Process API néhány hiányosságát.
A commons-exec műtárgy elérhető a Maven Central-tól:
org.apache.commons commons-exec 1.3
Most nézzük meg, hogyan tudjuk használni ezt a könyvtárat:
@Test public void givenPythonScript_whenPythonProcessExecuted_thenSuccess () dobja az ExecuteException, IOException {String line = "python" + ResolPythonScriptPath ("hello.py"); CommandLine cmdLine = CommandLine.parse (sor); ByteArrayOutputStream outputStream = új ByteArrayOutputStream (); PumpStreamHandler streamHandler = új PumpStreamHandler (outputStream); DefaultExecutor végrehajtó = new DefaultExecutor (); végrehajtó.setStreamHandler (streamHandler); int exitCode = végrehajtó.execute (cmdLine); assertEquals ("Nem szabad hibát észlelni", 0, exitCode); assertEquals ("Szkript kimenetet kell tartalmaznia:", "Helló Baeldung olvasók !!", outputStream.toString () .trim ()); }
Ez a példa nem túl különbözik az első példánktól ProcessBuilder. Létrehozunk egy Parancs sor objektum a megadott parancsunkra. Ezután beállítottunk egy adatfolyam-kezelőt, amely a folyamat kimenetének rögzítésére szolgál, mielőtt végrehajtanánk a parancsunkat.
Összefoglalva, a könyvtár fő filozófiája az, hogy olyan folyamat végrehajtási csomagot kínál, amelynek célja az operációs rendszerek széles körének támogatása egy következetes API-n keresztül.
6. A HTTP használata az interoperabilitáshoz
Tegyünk egy lépést egy pillanatra, és ahelyett, hogy megpróbálnánk a Python-ot közvetlenül meghívni, fontolóra vegyük egy jól bejáratott protokoll, például a HTTP, mint absztrakciós réteg használatát a két különböző nyelv között.
Valójában a Python egy egyszerű beépített HTTP szerverrel szállít, amelyet tartalmak vagy fájlok HTTP-n keresztüli megosztására használhatunk:
python -m http.szerver 9000
Ha most elmegyünk // localhost: 9000, látni fogjuk annak a könyvtárnak a tartalmát, ahol az előző parancsot elindítottuk.
Néhány más népszerű keretrendszer, amelyet fontolóra vehetünk a robusztusabb Python-alapú webszolgáltatások vagy alkalmazások létrehozásához, a Flask és a Django.
Miután rendelkezünk egy végponttal, amelyhez hozzáférhetünk, a több Java HTTP könyvtár bármelyikét felhasználhatjuk a Python webszolgáltatás / alkalmazás megvalósításunk meghívására.
7. Következtetés
Ebben az oktatóanyagban megismerkedtünk a Python kód Java-ból történő hívásának legnépszerűbb technológiáival.
Mint mindig, a cikk teljes forráskódja elérhető a GitHubon.