Py4J – мост между Python и Java

a4ec02uiv2tpxakenbyhtaygpxm.png

Название 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 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, но при этом не отличается высокой производительностью.

На правах рекламы


VDSina предлагает быстрые серверы в аренду под любые задачи, огромный выбор операционных систем для автоматической установки, есть возможность установить любую ОС с собственного ISO, удобная панель управления собственной разработки и посуточная оплата.

Подписывайтесь на наш чат в Telegram.

8p3vz47nluspfyc0axlkx88gdua.png

© Habrahabr.ru