Hvordan ringe Python fra Java

1. Oversikt

Python er et stadig mer populært programmeringsspråk, spesielt i det vitenskapelige samfunnet på grunn av sitt rike utvalg av numeriske og statistiske pakker. Derfor er det ikke et uvanlig krav å kunne påkalle Python-kode fra Java-applikasjonene våre.

I denne veiledningen, Vi tar en titt på noen av de vanligste måtene å ringe Python-kode fra Java.

2. Et enkelt Python-skript

Gjennom denne opplæringen bruker vi et veldig enkelt Python-skript som vi definerer i en dedikert fil som heter hei.py:

utskrift ("Hello Baeldung Readers !!")

Forutsatt at vi har en fungerende Python-installasjon, når vi kjører skriptet, bør vi se meldingen skrevet ut:

$ python hello.py Hei Baeldung Lesere !!

3. Core Java

I denne delen ser vi på to forskjellige alternativer vi kan bruke til å påkalle Python-skriptet vårt ved hjelp av kjernen Java.

3.1. Ved hjelp av ProcessBuilder

La oss først se på hvordan vi kan bruke ProcessBuilder API for å lage en egen operativsystemprosess for å starte python og utfør vårt enkle skript:

@Test offentlig ugyldighet gittPythonScript_whenPythonProcessInvoked_thenSuccess () kaster unntak {ProcessBuilder processBuilder = ny ProcessBuilder ("python", resolutionPythonScriptPath ("hallo.py")); processBuilder.redirectErrorStream (true); Prosessprosess = processBuilder.start (); Liste resultater = readProcessOutput (process.getInputStream ()); assertThat ("Resultatene skal ikke være tomme", resultater, er (ikke (tomme ()))); assertThat ("Resultatene skal inneholde utdata fra skriptet:", results, hasItem (inneholderString ("Hello Baeldung Readers !!"))); int exitCode = process.waitFor (); assertEquals ("Ingen feil skal oppdages", 0, exitCode); }

I dette første eksemplet kjører vi python kommando med ett argument som er den absolutte veien til vår hei.py manus. Vi finner den i vår test / ressurser mappe.

For å oppsummere lager vi vårt ProcessBuilder objekt som sender kommando- og argumentverdiene til konstruktøren. Det er også viktig å nevne samtalen til redirectErrorStream (true). I tilfelle feil, blir feilutdata slått sammen med standardutdata.

Dette er nyttig ettersom det betyr at vi kan lese eventuelle feilmeldinger fra den tilsvarende utgangen når vi ringer til getInputStream () metoden på Prosess gjenstand. Hvis vi ikke setter denne eiendommen til ekte, så må vi lese utdata fra to separate strømmer ved hjelp av getInputStream () og getErrorStream () metoder.

Nå starter vi prosessen med start() metode for å få en Prosess gjenstand. Deretter leser vi prosessutgangen og verifiserer at innholdet er det vi forventer.

Som tidligere nevnt har vi lagt til grunn at python kommandoen er tilgjengelig via STI variabel.

3.2. Arbeide med JSR-223 Scripting Engine

JSR-223, som først ble introdusert i Java 6, definerer et sett med skript-APIer som gir grunnleggende skriptfunksjonalitet. Disse metodene gir mekanismer for å utføre skript og for å dele verdier mellom Java og et skriptspråk. Hovedmålet med denne standarden var å prøve å få litt ensartethet i samhandling med forskjellige skriptspråk fra Java.

Vi kan bruke den pluggbare skriptmotorarkitekturen til ethvert dynamisk språk forutsatt at den har en JVM-implementering, selvfølgelig. Jython er Java-plattformimplementeringen av Python som kjører på JVM.

Forutsatt at vi har Jython på CLASSPATH, bør rammeverket automatisk oppdage at vi har muligheten til å bruke denne skriptmotoren og gjøre det mulig for oss å be om Python-skriptmotoren direkte.

Siden Jython er tilgjengelig fra Maven Central, kan vi bare inkludere det i vårt pom.xml:

 org.python jython 2.7.2 

På samme måte kan den også lastes ned og installeres direkte.

La oss liste ut alle skriptmotorer som vi har tilgjengelig for oss:

ScriptEngineManagerUtils.listEngines ();

Hvis vi har muligheten til å bruke Jython, bør vi se den aktuelle skriptmotoren vises:

... Motornavn: jython Versjon: 2.7.2 Språk: python Korte navn: python jython 

Nå som vi vet at vi kan bruke Jython-skriptmotoren, la oss gå videre og se hvordan vi kan kalle vår hei.py manus:

@Test offentlig ugyldighet gittPythonScriptEngineIsAvailable_whenScriptInvoked_thenOutputDisplayed () kaster Unntak {StringWriter skribent = ny StringWriter (); ScriptContext context = ny SimpleScriptContext (); context.setWriter (skribent); ScriptEngineManager manager = ny ScriptEngineManager (); ScriptEngine engine = manager.getEngineByName ("python"); engine.eval (ny FileReader (resolvePythonScriptPath ("hallo.py")), kontekst); assertEquals ("Bør inneholde skriptutgang:", "Hello Baeldung Readers !!", writer.toString (). trim ()); }

Som vi kan se, er det ganske enkelt å jobbe med denne API-en. Først begynner vi med å sette opp en ScriptContext som inneholder en StringWriter. Dette vil bli brukt til å lagre utdataene fra skriptet vi vil påberope.

Vi bruker deretter getEngineByName metoden for ScriptEngineManager klasse for å slå opp og lage en ScriptEngine for et gitt kortnavn. I vårt tilfelle kan vi passere python eller jython som er de to korte navnene som er knyttet til denne motoren.

Som før er det siste trinnet å få utdataene fra skriptet vårt og sjekke at det samsvarer med det vi forventet.

4. Jython

Fortsetter du med Jython, har vi også muligheten til å legge Python-kode direkte inn i Java-koden vår. Vi kan gjøre dette ved hjelp av PythonInterpretor klasse:

@Test offentlig ugyldighet gittPythonInterpreter_whenPrintExecuted_thenOutputDisplayed () {try (PythonInterpreter pyInterp = new PythonInterpreter ()) {StringWriter output = new StringWriter (); pyInterp.setOut (utgang); pyInterp.exec ("print ('Hello Baeldung Readers !!')"); assertEquals ("Skal inneholde skriptutgang:", "Hei Baeldung-lesere !!", output.toString () .trim ()); }}

Bruker PythonInterpreter klasse lar oss utføre en streng med Python kildekode via utføre metode. Som før bruker vi a StringWriter for å fange utdataene fra denne utførelsen.

La oss nå se et eksempel der vi legger to tall sammen:

@Test offentlig ugyldighet gittPythonInterpreter_whenNumbersAdded_thenOutputDisplayed () {try (PythonInterpreter pyInterp = new PythonInterpreter ()) {pyInterp.exec ("x = 10 + 10"); PyObject x = pyInterp.get ("x"); assertEquals ("x:", 20, x.asInt ()); }}

I dette eksemplet ser vi hvordan vi kan bruke metode for å få tilgang til verdien til en variabel.

I vårt siste Jython-eksempel ser vi hva som skjer når det oppstår en feil:

prøv (PythonInterpreter pyInterp = ny PythonInterpreter ()) {pyInterp.exec ("import-syds"); }

Når vi kjører denne koden a PyException blir kastet og vi får se den samme feilen som om vi jobbet med innfødt Python:

Sporing (siste anrop sist): Fil "", linje 1, i ImportError: Ingen modul som heter syds

Noen få punkter vi bør merke oss:

  • Som PythonIntepreter redskaper Kan lukkes automatisk, det er god praksis å bruke prøv-med-ressurser når du jobber med denne klassen
  • De PythonInterpreter klassenavn innebærer ikke at vår Python-kode tolkes. Python-programmer i Jython drives av JVM og blir derfor samlet til Java bytecode før kjøring
  • Selv om Jython er Python-implementeringen for Java, kan det hende at den ikke inneholder alle de samme delpakker som innfødt Python

5. Apache Commons Exec

Et annet tredjepartsbibliotek som vi kan vurdere å bruke er Apache Common Exec som prøver å overvinne noen av manglene ved Java Process API.

De commons-exec artefakt er tilgjengelig fra Maven Central:

 org.apache.commons commons-exec 1.3 

La oss nå hvordan vi kan bruke dette biblioteket:

@Test offentlig ugyldighet gittPythonScript_whenPythonProcessExecuted_thenSuccess () kaster ExecuteException, IOException {String line = "python" + resolvePythonScriptPath ("hallo.py"); CommandLine cmdLine = CommandLine.parse (linje); ByteArrayOutputStream outputStream = ny ByteArrayOutputStream (); PumpStreamHandler streamHandler = ny PumpStreamHandler (outputStream); DefaultExecutor executor = ny DefaultExecutor (); executor.setStreamHandler (streamHandler); int exitCode = executor.execute (cmdLine); assertEquals ("Ingen feil skal oppdages", 0, exitCode); assertEquals ("Bør inneholde skriptutgang:", "Hallo Baeldung-lesere !!", outputStream.toString () .trim ()); }

Dette eksemplet er ikke så ulikt vårt første eksempel ProcessBuilder. Vi lager en Kommandolinje objekt for vår gitte kommando. Deretter setter vi opp en strømbehandler som skal brukes til å fange utdataene fra prosessen vår før vi utfører kommandoen.

For å oppsummere er hovedfilosofien bak dette biblioteket å tilby en prosessutførelsespakke rettet mot å støtte et bredt spekter av operativsystemer gjennom en konsistent API.

6. Bruke HTTP for interoperabilitet

La oss ta et skritt tilbake et øyeblikk, og i stedet for å prøve å påkalle Python, bør du vurdere å bruke en veletablert protokoll som HTTP som et abstraksjonslag mellom de to forskjellige språkene.

Faktisk leveres Python med en enkel innebygd HTTP-server som vi kan bruke til å dele innhold eller filer via HTTP:

python -m http.server 9000

Hvis vi nå går til // lokal vert: 9000, vil vi se innholdet som er oppført for katalogen der vi lanserte forrige kommando.

Noen andre populære rammer vi kan vurdere å bruke for å lage mer robuste Python-baserte webtjenester eller applikasjoner er Flask og Django.

Når vi har et endepunkt vi har tilgang til, kan vi bruke et av flere Java HTTP-biblioteker til å påkalle vår Python-nettjeneste / applikasjonsimplementering.

7. Konklusjon

I denne opplæringen har vi lært om noen av de mest populære teknologiene for å ringe Python-kode fra Java.

Som alltid er hele kildekoden til artikkelen tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found