Название Py4J можно встретить разве что в списке библиотек, используемых PySpark, но не стоит недооценивать данный инструмент, который обеспечивает совместную работу Python и Java. В этой статье будет кратко описана работа Py4J, рассмотрен пример использования и перечислены сильные и слабые стороны библиотеки. В конце будут описаны альтернативные способы связи Java и Python.
Py4J позволяет программам, работающим в интерпретаторе Python, динамически обращаться к объектам Java внутри JVM. Методы вызываются так, как если бы объекты Java находились в интерпретаторе Python, а доступ к коллекциям Java можно было получить с помощью стандартных методов коллекций Python. Py4J также позволяет программам Java вызывать объекты Python, но на этом возможности библиотеки не заканчиваются. Py4J позволяет создавать из Python классические коллекции Java, а именно Array, List, Set и Map. Также можно конвертировать Python коллекции в Java коллекции. Ещё из Python возможно реализовывать интерфейсы, которые описаны в Java.
Существует несколько альтернатив, например, Jython. В отличие от него, Py4J не выполняет код Python в JVM, поэтому при использовании Py4J можно работать со всеми библиотеками классического Cython. Ещё есть JPype, но Py4J не связывает потоки Python и Java, также он использует сокеты, а не JNI для связи с JVM.
Главным минусом Py4J является скорость передачи данных между Python и Java. Так как общение происходит посредством сокетов, передавать данные, размером больше чем несколько мегабайт, будет плохой идеей, для этой цели существуют другие решения. Главная задача Py4J – обеспечить доступ к объектам Java и сохранить возможность использования Python библиотек.
Для примера будет создано три Java класса и один Python скрипт для проверки работы. Класс Dict, в котором реализована логика работы с HashMap, Класс DictEntryPoint, в котором реализована точка входа, чтобы Python мог взаимодействовать с объектом класса Dict. Также нужен класс Program, в котором происходит запуск сервера.
Для успешной работы Py4J нужно настроить точку входа, в которой создать необходимые для работы объекты, и запустить GatewayServer, который обеспечивает связь Python с JVM через сокет локальной сети. Далее можно спокойно использовать Java код из Python.
Dict.java
package py4j_example;
import java.util.HashMap;
public class Dict {
private HashMap<Integer, String> dict = new HashMap<>();
/**
* Добавление элемента по ключу
*/
public void add(Integer key, String value) {
dict.put(key, value);
}
/**
* Добавляет значение в конец HashMap
*/
public void add(String value) {
dict.put(dict.size(), value);
}
/**
* Удаляет значение по ключу
*/
public String remove(Integer key) {
return dict.remove(key);
}
/**
* Возвращает значение по ключу
*/
public String get(Integer key) {
return dict.get(key);
}
/**
* Возвращает длину HashMap
*/
public int length() {
return dict.size();
}
/**
* Пересоздаёт HashMap
*/
public void clear() {
dict = new HashMap<>();
add("Запись из Java");
}
}
DictEntryPoint.java
package py4j_example;
import py4j.GatewayServer;
public class DictEntryPoint {
private final Dict dict;
/**
* Создаёт объект класса Dict
*/
public DictEntryPoint() {
this.dict = new Dict();
}
/**
* Возвращает объект класса Dict
*/
public Dict getDict() {
return this.dict;
}
}
Program.java
package py4j_example;
import py4j.GatewayServer;
public class Program {
public static void main(String[] args) {
/* Создание и запуск сервера */
GatewayServer gatewayServer = new GatewayServer(new DictEntryPoint());
gatewayServer.start();
System.out.println("Gateway Server Started");
}
}
Вывод должен быть примерно такой. После запуска Program.java можно приступить к написанию Python кода для подключения к JVM.
Connected to the target VM, address: '127.0.0.1:58425', transport: 'socket'
Gateway Server Started
Application.py
from py4j.java_gateway import JavaGateway
def add_some_values(dict):
# Создание списка имён и их запись в dict
names = ["Вася", "Аня", "Лена", "Никита"]
for name in names:
dict.add(name)
# Удаление значения по ключу 4
deleted = dict.remove(4)
# Вывод содержимого dict
for i in range(dict.length()):
print(i, "\t", dict.get(i))
print("\nУдалённый элемент =", deleted)
return 1
def main():
# Инициализация JavaGateway
gateway = JavaGateway()
# Получение доступа к объекту класса Dict
dict = gateway.entry_point.getDict()
add_some_values(dict)
# Очистка Dict
dict.clear()
return 0
if __name__ == "__main__":
main()
После запуска Application.py в консоль выводится следующее:
0 Запись из Java
1 Вася
2 Аня
3 Лена
Удалённый элемент = Никита
По ключу 0 находится элемент, добавленный из Java, а имена людей были добавлены с помощью Python.
Py4J позволяет быстро и легко взаимодействовать с объектами Java из Python, организовывать двустороннее управление коллекциями и работать с интерфейсами в двух языках, соединяя интерпретатор и JVM сокетами. Он отлично подойдёт для задач, требующих минимальных ограничений на использование Python, но при этом не отличается высокой производительностью.
Источник статьи: https://habr.com/ru/company/vdsina/blog/555140/
Py4J позволяет программам, работающим в интерпретаторе Python, динамически обращаться к объектам Java внутри JVM. Методы вызываются так, как если бы объекты Java находились в интерпретаторе Python, а доступ к коллекциям Java можно было получить с помощью стандартных методов коллекций Python. Py4J также позволяет программам Java вызывать объекты Python, но на этом возможности библиотеки не заканчиваются. Py4J позволяет создавать из Python классические коллекции Java, а именно Array, List, Set и Map. Также можно конвертировать Python коллекции в Java коллекции. Ещё из Python возможно реализовывать интерфейсы, которые описаны в Java.
Существует несколько альтернатив, например, Jython. В отличие от него, Py4J не выполняет код Python в JVM, поэтому при использовании Py4J можно работать со всеми библиотеками классического Cython. Ещё есть JPype, но Py4J не связывает потоки Python и Java, также он использует сокеты, а не JNI для связи с JVM.
Главным минусом Py4J является скорость передачи данных между Python и Java. Так как общение происходит посредством сокетов, передавать данные, размером больше чем несколько мегабайт, будет плохой идеей, для этой цели существуют другие решения. Главная задача Py4J – обеспечить доступ к объектам Java и сохранить возможность использования Python библиотек.
Пример работы
Для примера будет создано три Java класса и один Python скрипт для проверки работы. Класс Dict, в котором реализована логика работы с HashMap, Класс DictEntryPoint, в котором реализована точка входа, чтобы Python мог взаимодействовать с объектом класса Dict. Также нужен класс Program, в котором происходит запуск сервера.
Для успешной работы Py4J нужно настроить точку входа, в которой создать необходимые для работы объекты, и запустить GatewayServer, который обеспечивает связь Python с JVM через сокет локальной сети. Далее можно спокойно использовать Java код из Python.
Dict.java
package py4j_example;
import java.util.HashMap;
public class Dict {
private HashMap<Integer, String> dict = new HashMap<>();
/**
* Добавление элемента по ключу
*/
public void add(Integer key, String value) {
dict.put(key, value);
}
/**
* Добавляет значение в конец HashMap
*/
public void add(String value) {
dict.put(dict.size(), value);
}
/**
* Удаляет значение по ключу
*/
public String remove(Integer key) {
return dict.remove(key);
}
/**
* Возвращает значение по ключу
*/
public String get(Integer key) {
return dict.get(key);
}
/**
* Возвращает длину HashMap
*/
public int length() {
return dict.size();
}
/**
* Пересоздаёт HashMap
*/
public void clear() {
dict = new HashMap<>();
add("Запись из Java");
}
}
DictEntryPoint.java
package py4j_example;
import py4j.GatewayServer;
public class DictEntryPoint {
private final Dict dict;
/**
* Создаёт объект класса Dict
*/
public DictEntryPoint() {
this.dict = new Dict();
}
/**
* Возвращает объект класса Dict
*/
public Dict getDict() {
return this.dict;
}
}
Program.java
package py4j_example;
import py4j.GatewayServer;
public class Program {
public static void main(String[] args) {
/* Создание и запуск сервера */
GatewayServer gatewayServer = new GatewayServer(new DictEntryPoint());
gatewayServer.start();
System.out.println("Gateway Server Started");
}
}
Вывод должен быть примерно такой. После запуска Program.java можно приступить к написанию Python кода для подключения к JVM.
Connected to the target VM, address: '127.0.0.1:58425', transport: 'socket'
Gateway Server Started
Application.py
from py4j.java_gateway import JavaGateway
def add_some_values(dict):
# Создание списка имён и их запись в dict
names = ["Вася", "Аня", "Лена", "Никита"]
for name in names:
dict.add(name)
# Удаление значения по ключу 4
deleted = dict.remove(4)
# Вывод содержимого dict
for i in range(dict.length()):
print(i, "\t", dict.get(i))
print("\nУдалённый элемент =", deleted)
return 1
def main():
# Инициализация JavaGateway
gateway = JavaGateway()
# Получение доступа к объекту класса Dict
dict = gateway.entry_point.getDict()
add_some_values(dict)
# Очистка Dict
dict.clear()
return 0
if __name__ == "__main__":
main()
После запуска Application.py в консоль выводится следующее:
0 Запись из Java
1 Вася
2 Аня
3 Лена
Удалённый элемент = Никита
По ключу 0 находится элемент, добавленный из Java, а имена людей были добавлены с помощью Python.
Заключение
Py4J позволяет быстро и легко взаимодействовать с объектами Java из Python, организовывать двустороннее управление коллекциями и работать с интерфейсами в двух языках, соединяя интерпретатор и JVM сокетами. Он отлично подойдёт для задач, требующих минимальных ограничений на использование Python, но при этом не отличается высокой производительностью.
Источник статьи: https://habr.com/ru/company/vdsina/blog/555140/