Одной из наиболее интересных особенностей 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. Для этого давайте определим нашу sumfunction как обычную функцию 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 🍕 )