Одной из наиболее интересных особенностей CPython
является возможность добавлять новые встроенные модули в Python, написанные на C. Python предоставляет полезное C Api
для этого, набор заголовков и основных типов для написания расширений на C, включенных в исходный файл C. включив заголовок Python.h
В этой статье я дам вам обзор того, как расширить Python 3 с помощью C, а затем мы попытаемся сделать то же самое, используя современный язык, такой как Go.
Начнем с буквы C
Предположим, вы хотите создать новый модуль для вычисления сумм, например,
Следуя обширному разделу Python в документации, вы можете создать свой newmath.c
Затем, скомпилировав его как общую библиотеку
gcc newmath.c -shared -o newmath.so `pkg-config --cflags --libs python3`
вы получите новый модуль, который можно импортировать в свой код Python.
Расширение Python с помощью Go
Go lang - действительная альтернатива C, если вы хотите расширить Python: он проще, чем C, имеет сборщик мусора, обеспечивает отличную производительность, а параллельное выполнение кода с использованием подпрограмм Go действительно просто.
В Go SDK есть удивительный набор инструментов под названием cgo
, который позволяет программам Go взаимодействовать с C и позволяет создавать общие библиотеки из Go, автоматически создавая заголовки C из ваших методов в Go.
Мы используем волшебное пространство имен C. * для доступа к чему-либо из мира C и переписываем тот же код, который мы написали на C.
В этом случае вы должны определить преамбулу перед импортом «C» с комментариями, используемыми в качестве заголовка при компиляции частей C пакета: он может содержать любой код C, включая объявления и определения функций и переменных, и затем на него можно ссылаться из Используйте код Go, как если бы они были определены в пакете «C».
Ограничения этого подхода
Это отличный способ поиграть с миром C из Go, но я не предпочитаю его. Одним из самых больших ограничений этого подхода является то, что cgo не поддерживает вариативные функции, поэтому нам нужно обернуть PyArg_ParseTuple
в другую функцию.
Во время своих экспериментов, погружаясь в исходный код Python 3, я также обнаружил, что PyLong_Check
не является функцией, это макрос, и макро-функции также должны быть обернуты (источник: include / python3.6 / listobject.h ).
Более подходящий подход
Другой способ расширить Python с помощью Go - это переместить все элементы Py в C и просто вызвать функцию Go внутри C. Для этого давайте определим нашу sum
function как обычную функцию Go.
а затем скомпилировать все с помощью
go build -buildmode=c-archive -o libnewmath.a
Вы получите два файла: наш архив libnewmath.a
, который нам нужно связать на последнем этапе, и заголовок libnewmath.h
содержащий
extern GoInt sum(GoInt p0, GoInt p1);
Теперь вам нужно включить его в_newmath.c
и обернуть sum
функцию
Примечание. Я добавляю _
, чтобы исключить файлы из сборки go.
Если вам лень писать весь этот шаблонный код, вы можете рассмотреть возможность использования PyBindGen, просто добавьте его к своим требованиям и следуйте документации
git+https://github.com/gjcarneiro/pybindgen.git#egg=pybindgen
Последний шаг
Хорошо, теперь нам нужно создать нашу последнюю общую библиотеку так же, как и раньше, связав libnewmath
gcc _newmath.c -shared -o newmath.so `pkg-config — cflags — libs python3` -L . -lnewmath
Это сгенерирует окончательный общий объектnewmath.so
, мы поместим все в папку и используем __init__.py
для экспорта всех необходимых нам общедоступных функций с простым from .newmath import sum
.
👨🏻💻 Вот несколько примеров.
В следующей статье мы поговорим о выступлениях, следите за обновлениями! (Превью в моих слайдах @ Python Pizza 2018 🍕 )