- Как вызвать Python Из Java
- 1. Обзор
- 2. Простой Скрипт На Python
- 3. Ядро Java
- 3.1. Использование ProcessBuilder
- 3.2. Работа Со Скриптовым Движком JSR-223
- 4. Джайтон
- 5. Apache Commons Exec
- 6. Использование HTTP для взаимодействия
- 7. Заключение
- Читайте ещё по теме:
- How to execute Python code in Java
- What is jep?
- Set up your environment
- Getting started
- Running a script
- Type conversion
Как вызвать Python Из Java
Изучите наиболее распространенные способы вызова кода Python из Java.
1. Обзор
Python становится все более популярным языком программирования, особенно в научном сообществе из-за его богатого разнообразия числовых и статистических пакетов. Поэтому нет ничего необычного в том, чтобы иметь возможность вызывать код Python из наших Java-приложений.
В этом уроке мы рассмотрим некоторые из наиболее распространенных способов вызова кода Python из Java.
2. Простой Скрипт На Python
В этом уроке мы будем использовать очень простой скрипт на Python, который мы определим в специальном файле с именем hello.py :
print("Hello Baeldung Readers!!")
Предполагая, что у нас есть работающая установка Python, при запуске нашего скрипта мы должны увидеть напечатанное сообщение:
$ python hello.py Hello Baeldung Readers!!
3. Ядро Java
В этом разделе мы рассмотрим два различных варианта, которые мы можем использовать для вызова нашего скрипта Python с использованием ядра Java.
3.1. Использование ProcessBuilder
Давайте сначала рассмотрим, как мы можем использовать API ProcessBuilder для создания собственного процесса операционной системы для запуска python и выполнения нашего простого сценария:
@Test public void givenPythonScript_whenPythonProcessInvoked_thenSuccess() throws Exception < ProcessBuilder processBuilder = new ProcessBuilder("python", resolvePythonScriptPath("hello.py")); processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); Listresults = readProcessOutput(process.getInputStream()); assertThat("Results should not be empty", results, is(not(empty()))); assertThat("Results should contain output of script: ", results, hasItem( containsString("Hello Baeldung Readers!!"))); int exitCode = process.waitFor(); assertEquals("No errors should be detected", 0, exitCode); >
В этом первом примере мы запускаем команду python с одним аргументом, который является абсолютным путем к вашему hello.py сценарий. Мы можем найти его в нашей папке test/resources .
Подводя итог, мы создаем наш объект ProcessBuilder , передавая значения команды и аргумента конструктору. Также важно упомянуть вызов redirectErrorStream(true). В случае каких-либо ошибок вывод ошибок будет объединен со стандартным выводом.
Это полезно, поскольку означает, что мы можем считывать любые сообщения об ошибках из соответствующего вывода при вызове метода getInputStream() для объекта Process . Если мы не установим этому свойству значение true , то нам нужно будет считывать выходные данные из двух отдельных потоков, используя методы getInputStream() и getErrorStream () .
Теперь мы запускаем процесс с помощью метода start () , чтобы получить объект Process . Затем мы читаем выходные данные процесса и проверяем, что содержимое соответствует нашим ожиданиям.
Как уже упоминалось ранее, мы сделали предположение, что питон команда доступна через ПУТЬ переменная.
3.2. Работа Со Скриптовым Движком JSR-223
JSR-223 , который был впервые представлен в Java 6, определяет набор API-интерфейсов сценариев, которые обеспечивают базовую функциональность сценариев. Эти методы предоставляют механизмы для выполнения сценариев и обмена значениями между Java и языком сценариев. Основная цель этого стандарта состояла в том, чтобы попытаться привнести некоторое единообразие во взаимодействие с различными языками сценариев из Java.
Мы можем использовать подключаемую архитектуру скриптового движка для любого динамического языка при условии, конечно, что он имеет реализацию JVM . Jython – это реализация платформы Java Python, которая работает на JVM.
Предполагая , что у нас есть Jython в CLASSPATH , фреймворк должен автоматически обнаружить, что у нас есть возможность использовать этот механизм сценариев, и позволить нам напрямую запросить механизм сценариев Python.
Поскольку Jython доступен из Maven Central , мы можем просто включить его в ваш pom.xml :
Аналогично, он также может быть загружен и установлен напрямую.
Давайте перечислим все скриптовые движки, которые у нас есть в наличии:
ScriptEngineManagerUtils.listEngines();
Если у нас есть возможность использовать Jython, мы должны увидеть соответствующий скриптовый движок:
. Engine name: jython Version: 2.7.2 Language: python Short Names: python jython
Теперь, когда мы знаем, что можем использовать скриптовый движок Jython, давайте продолжим и посмотрим, как вызвать hello.py скрипт:
@Test public void givenPythonScriptEngineIsAvailable_whenScriptInvoked_thenOutputDisplayed() throws Exception
Как мы видим, работать с этим API довольно просто. Во-первых, мы начнем с настройки ScriptContext , который содержит StringWriter . Это будет использоваться для хранения выходных данных скрипта, который мы хотим вызвать.
Затем мы используем метод getEngineByName класса ScriptEngineManager для поиска и создания скриптового движка для заданного короткого имени . В нашем случае мы можем передать python или jython , которые являются двумя короткими именами, связанными с этим движком.
Как и прежде, последний шаг-получить выходные данные из нашего скрипта и проверить, соответствует ли он тому, что мы ожидали.
4. Джайтон
Продолжая работу с Jython, у нас также есть возможность встраивать код Python непосредственно в наш Java-код. Мы можем сделать это с помощью класса Pythoninterpreter :
@Test public void givenPythonInterpreter_whenPrintExecuted_thenOutputDisplayed() < try (PythonInterpreter pyInterp = new PythonInterpreter()) < StringWriter output = new StringWriter(); pyInterp.setOut(output); pyInterp.exec("print('Hello Baeldung Readers!!')"); assertEquals("Should contain script output: ", "Hello Baeldung Readers!!", output.toString() .trim()); >>
Использование класса PythonInterpreter позволяет нам выполнить строку исходного кода Python с помощью метода exec /. Как и прежде, мы используем StringWriter для захвата выходных данных этого выполнения.
Теперь давайте рассмотрим пример, где мы складываем два числа вместе:
@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 для доступа к значению переменной.
В нашем последнем примере Jython мы увидим, что происходит, когда возникает ошибка:
try (PythonInterpreter pyInterp = new PythonInterpreter())
Когда мы запускаем этот код, возникает Исключение , и мы увидим ту же ошибку, как если бы мы работали с собственным Python:
Traceback (most recent call last): File "", line 1, in ImportError: No module named syds
Несколько моментов, которые мы должны отметить:
- Поскольку Интерпретатор Python реализует Автоклавируемый , рекомендуется использовать try-with-resources при работе с этим классом
- Имя класса PythonInterpreter не означает, что наш код Python интерпретируется. Программы Python в Python запускаются JVM и поэтому компилируются в байт-код Java перед выполнением
- Хотя Jython является реализацией Python для Java, он может содержать не все те же подпакеты, что и родной Python
5. Apache Commons Exec
Еще одной сторонней библиотекой, которую мы могли бы рассмотреть, является Apache Common Exec , которая пытается преодолеть некоторые недостатки API процесса Java|/.
Артефакт commons-exec доступен в Maven Central :
org.apache.commons commons-exec 1.3
Теперь давайте посмотрим, как мы можем использовать эту библиотеку:
@Test public void givenPythonScript_whenPythonProcessExecuted_thenSuccess() throws ExecuteException, IOException
Этот пример не слишком отличается от нашего первого примера с использованием ProcessBuilder . Мы создаем объект командной строки для данной команды. Затем мы настроим обработчик потока, который будет использоваться для захвата выходных данных нашего процесса перед выполнением вашей команды.
Подводя итог, можно сказать, что основная философия этой библиотеки заключается в том, чтобы предложить пакет выполнения процессов, направленный на поддержку широкого спектра операционных систем с помощью согласованного API.
6. Использование HTTP для взаимодействия
Давайте сделаем шаг назад на мгновение и вместо того, чтобы пытаться напрямую вызывать Python, рассмотрим использование хорошо зарекомендовавшего себя протокола, такого как HTTP, в качестве уровня абстракции между двумя разными языками.
На самом деле Python поставляется с простым встроенным HTTP-сервером, который мы можем использовать для обмена контентом или файлами по HTTP :
Если мы сейчас перейдем к http://localhost:9000 , мы увидим содержимое каталога, в котором мы запустили предыдущую команду.
Некоторые другие популярные фреймворки, которые мы могли бы использовать для создания более надежных веб-сервисов или приложений на основе Python, Колба и Джанго .
Как только у нас есть конечная точка, к которой мы можем получить доступ, мы можем использовать любую из нескольких библиотек Java HTTP для вызова нашей реализации веб-службы/приложения Python.
7. Заключение
В этом уроке мы узнали о некоторых из самых популярных технологий для вызова кода Python из Java.
Как всегда, полный исходный код статьи доступен на GitHub .
Читайте ещё по теме:
How to execute Python code in Java
In this tutorial we will show you how to integrate Java and Python code in an almost seamless manner with just a few easy steps.
What is jep?
Jep is an open source library which gives you the ability to execute Python code in Java and vice versa.
Let’s say you have an existing Java application and you need to use some 3rd party library. Unfortunately, this library is implemented only in Python so you can’t really use it as is as part of your application. Jep will help you solve that exact problem.
On a side note, there are other libraries that will help you achieve the same goal like jpy and jython for example, but they are less popular or not as actively maintained as Jep is.
Set up your environment
- JDK — Jep uses JNI in order to execute Python code, so running your application with JRE will not suffice since it doesn’t include the required JNI module.
- Python — both Python 2.x and 3.x is supported
- Install Jep Python library, simply run:
- Install Jep Java library. In case you are using gradle, for example, add the following dependency to your build.gradle:
implementation group: 'black.ninia', name: 'jep', version: '3.9.1'
- Finally, you’ll need to inject your Java application with a new JVM argument pointing to your Jep Python library installation directory, for example:
-Djava.library.path=/Users/YOUR_USERNAME>/Library/Python/3.9/lib/python/site-packages/jep
Getting started
Now that everything is setup, we will show you how to work with Jep.
First we’ll need to create a new SharedInterpreter instance which we will use throughout our Java code.
Then, using that interpreter, we will:
- Inject a String argument which will be used by the Python code: Our Python script argument named user_name will get the value of our Java code name variable.
- Execute the Python code using exec() method
- Get a return value from Python back to Java
That’s it. It’s as simple as that.
Now you can install any Python library you need, import it in your Python code and then execute it as part of your Java code.
Running a script
The more common use case for Jep is running an entire Python script with a single Java command. This way you don’t need to call the exec() method over and over again for each Python code line you have.
This approach is very useful in case you have an existing Python code which you want executed as part of your Java application.
Type conversion
Every Java type being sent to Python using the interpreter is being converted to its counterpart. This applies to both primitives and complex data structures like objects and collections.
So, for example Python’s list will be converted into Java’s ArrayList and Python’s dict will be converted into Java’s HashMap, etc. Everything is done automatically so you don’t have to worry about it.
For a full of type conversion, see this link.