Skip to content

Python пакеты на Rust-е

Начинаем делать Python либу на Rust-е.

Я выступал с докладом по этой теме на PiterPy 2023. Видео можно посмотреть здесь.

Сейчас я хочу текстом описать процесс создания проекта и в будущем возможно будут другие гайды на что стоит обратить внимание при использовании Rust в Python.

Почему Rust? Ведь есть множество других способов написать производительный код. И да, в первую очередь мы используем другой язык программирования, чтобы ускорить Python.

Альтерантивы

  • Cython
  • Numba
  • ctypes — модуль для интеграции с языком С.

Как альтернативу, я бы ещё добавил NumPy и подобные ему инструменты, так как можно сильно ускорить работу программы, начав использовать их.

Самый главный плюс — это Rust. И вот почему...

Помимо очевидных плюсов, которые предоставляет данный язык:

  • скорость
  • безопасность
  • качество

Это большое сообщество разработчиков и большое количество библиотек. Если у вас возникнут проблемы, скорее всего быстро найдутся умельцы, которые вам помогут.

Самый главный плюс — это готовые библиотеки для интеграции Rust и Python. Используя их, вам не нужно выполнять пляски с бубном. Просто пишите код на одном языке и далее нативно его используете в другом.

Когда нужно использовать Rust?

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

  • сериализация и десериализация данных — например, парсинг JSON
  • шифрование и дешифрование
  • конструкции for in и различные вычисления с большим объемом данных

Зачастую пригодится тем, кто выполняет статистические расчеты в своих проектах. Во всех остальных случаях скорее всего вам нужно решить архитектурно проблему. Например, делать систему масштабируемой.

Плюс Rust можно использовать как DSL для вашей БЛ (бизнес логики). Rust имеет очень сильную систему типов и подскажет вам, если вы допустили ошибку.

PyO3

Полное название Pythonium Trioxide. Сейчас самый популярный инструмент для связки Rust и Python, ИМХО.

Предоставляет высокоуровневый интерфейс и вам не нужно задумываться об интеграции Rust кода с Python кодом.

Создание проекта

maturin — пакетный менеджер для Python проектов, которые используют Rust.

Он нужен для создания структуры проекта. Одной командой у нас появляются pyproject.toml, Cargo.toml и Github actions джобы для деплоя нашего проекта на pypi.

maturin init
ls
.github/
  workflows/
    maturin.init
src/
  lib.rs
pyproject.toml
Cargo.toml

У нас почти все готово, осталось выполнить:

maturin develop

Обратите внимание, что Rust код скомпируется в dev режиме. Ваши бенчмарки будут работать медленнее, чем в release режиме. Чтобы исправить это, нужно выполнить добавить флаг -r:

maturin develop -r

Испольуем модуль в Python просто импортировав его:

import package

Python обёртка

Вы можете рядом держать Python код, чтобы упростить интерфейс использования вашей программы. Также, не мало важно, описать типы, которые необходимы для проверки через mypy, pyright и т.п.

Добавляем в pyproject.toml:

[tool.maturin]
module-name = "package._module"

И делаем название модуля в Rust:

#[pymodule]
fn _module(_py: Python, m: &PyModule) -> PyResult<()> {
    Ok(())
}

Таким образом, мы можем импортировать ваш Rust модуль в Python:

from package import _module
# from . import _module

Описываем типы в файле package/_module.pyi и не забываем добавить py.typed в пакет.

Публикация

Для публикации на pypi нужно создать аккаунт на pypi.org. Далее нужно создать токен и сохранить его в Github secrets под переменной PYPI_API_TOKEN. maturin сам соберет и опубликует ваш пакет через github actions.

Итог

Мы с вами научились создавать Python библиотеки на Rust (всего две команды). Теперь вы можете писать производительный код и использовать его в своих проектах. PyO3 имеет очень хорошую документацию и вы можете найти ответы на свои вопросы там. В данном гайде я не стал углубляться в детали, потому что мне лень, но буду потихоньку добавлять материал.

Основной минус для меня, что мы не можем использовать весь функционал Rust. Например, мы не можем использовать lifetime проверки, из-за чего код приходится писать по-другому. Также стоит уделить внимание бенчарком, чтобы сделать ваш код максимально быстрым. Многое зависит от размера данных, которые вы обрабатываете и как вы пишите код на Rust.

Ссылки

Comments