Вызов C / C++ из Python?

Каким будет самый быстрый способ создания привязки Python к библиотеке C или C++?

(Я использую Windows, если это важно.)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
545
0
459 336
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Самый быстрый способ сделать это - использовать SWIG.

Пример из SWIG руководство:

/* File : example.c */
int fact(int n) {
    if (n <= 1) return 1;
    else return n*fact(n-1);
}

Файл интерфейса:

/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}

extern int fact(int n);

Сборка модуля Python в Unix:

swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so

Использование:

>>> import example
>>> example.fact(5)
120

Обратите внимание, что у вас должен быть python-dev. Также в некоторых системах файлы заголовков python будут находиться в /usr/include/python2.7 в зависимости от того, как вы их установили.

Из учебника:

SWIG is a fairly complete C++ compiler with support for nearly every language feature. This includes preprocessing, pointers, classes, inheritance, and even C++ templates. SWIG can also be used to package structures and classes into proxy classes in the target language — exposing the underlying functionality in a very natural manner.

Ответ принят как подходящий

Вам стоит взглянуть на Boost.Python. Вот краткое введение с их веб-сайта:

The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools -- just your C++ compiler. It is designed to wrap C++ interfaces non-intrusively, so that you should not have to change the C++ code at all in order to wrap it, making Boost.Python ideal for exposing 3rd-party libraries to Python. The library's use of advanced metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).

Boost.Python - одна из наиболее удобных для пользователя библиотек в Boost, для простого API вызова функций она довольно проста и предоставляет шаблон, который вам придется написать самостоятельно. Это немного сложнее, если вы хотите предоставить объектно-ориентированный API.

jwfearn 28.09.2008 20:39

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

miller 18.09.2018 12:58

Спустя почти 11 лет пора задуматься о качестве этого ответа?

J Evans 23.05.2019 22:59

Это все еще лучший подход к интерфейсу python и C++?

tushaR 17.06.2019 05:28

Возможно, вы можете попробовать pybind11, который легче по сравнению с boost.

jdhao 16.07.2019 15:46

Модуль ctypes является частью стандартной библиотеки и поэтому более стабилен и широко доступен, чем глоток, который всегда давал мне проблемы.

С ctypes вам необходимо удовлетворить любую зависимость времени компиляции от python, и ваша привязка будет работать на любом питоне, имеющем ctypes, а не только на том, для которого он был скомпилирован.

Предположим, у вас есть простой пример класса C++, с которым вы хотите поговорить, в файле с именем foo.cpp:

#include <iostream>

class Foo{
    public:
        void bar(){
            std::cout << "Hello" << std::endl;
        }
};

Поскольку ctypes могут взаимодействовать только с функциями C, вам необходимо предоставить те, которые объявляют их как extern "C"

extern "C" {
    Foo* Foo_new(){ return new Foo(); }
    void Foo_bar(Foo* foo){ foo->bar(); }
}

Затем вам нужно скомпилировать это в общую библиотеку

g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

И, наконец, вам нужно написать свою оболочку python (например, в fooWrapper.py)

from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')

class Foo(object):
    def __init__(self):
        self.obj = lib.Foo_new()

    def bar(self):
        lib.Foo_bar(self.obj)

Как только у вас есть это, вы можете называть это как

f = Foo()
f.bar() #and you will see "Hello" on the screen

Это в значительной степени то, что делает за вас boost.python за один вызов функции.

Martin Beckett 29.09.2008 20:36

ctypes находится в стандартной библиотеке python, swig и boost - нет. Swig и boost полагаются на модули расширения и поэтому привязаны к второстепенным версиям Python, а независимые общие объекты - нет. создание обертки swig или boost может быть проблемой, ctypes не требует сборки.

Florian Bösch 30.09.2008 02:42

boost полагается на магию шаблонов voodoo и полностью настраиваемую систему сборки, ctypes полагается на простоту. ctypes - динамический, boost - статический. ctypes могут обрабатывать разные версии библиотек. буст не может.

Florian Bösch 30.09.2008 02:44

mgb: но вы меня разозлили из-за буста, я бы посоветовал вам написать ответ самостоятельно. Однако, чтобы продемонстрировать превосходство над ctypes, это должен быть тот же пример, менее 4 строк кода оболочки C++, менее 2 строк инструкций по сборке и никаких строк python, ну и поместите его на один экран.

Florian Bösch 30.09.2008 02:51

Договорились: у меня тоже проблемы с глотком и наддувом. Вы должны четко указать в своем ответе, какие это файлы и какое имя им нужно получить.

Davide 14.11.2009 08:45

В Windows мне пришлось указать __declspec (dllexport) в сигнатурах моих функций, чтобы Python мог их видеть. В приведенном выше примере это будет соответствовать: extern "C" { __declspec(dllexport) Foo* Foo_new(){ return new Foo(); } __declspec(dllexport) void Foo_bar(Foo* foo){ foo->bar(); } }

Alan Macdonald 30.11.2011 15:12

А как насчет передачи аргументов в bar ()? Возможно ли это сделать? Например, предположим, что вы хотите передать python dict в bar (), а bar () выполнить итерацию и распечатать каждый элемент.

Dustin Boswell 25.06.2013 01:31

Взгляните на ссылку ctypes, указанную в ответе. В основном вам нужно вручную преобразовать все аргументы в основные типы, известные C, иначе они интерпретируются как int. Вы можете определить свои собственные структуры вручную. Типы переменных, такие как Python dict, не поддерживаются, но, конечно, вы можете использовать взлом с указателями void, если это абсолютно необходимо. Пример двойного аргумента: lib.Foo_baz (self.obj, ctypes.c_double (3.5))

Fred Schoen 30.08.2013 18:43

+1 Отлично, спасибо! Возможно, это общеизвестно, но для будущих поколений я использовал osx и для компиляции пришлось заменить -soname на -install_name.

Darragh Enright 16.01.2014 21:49

В этом примере в указателях функций должны быть установлены restype и argtypes. restype по умолчанию - c_int, который усекает 64-битный указатель. В restype=c_void_p значение указателя защищено, но по-прежнему преобразуется в целое число Python. В качестве аргумента это снова значение по умолчанию c_int, если только argtypes не указан или он вручную не завернут в c_void_p.

Eryk Sun 01.04.2014 01:31

@DustinBoswell: я расширил код этого ответа, включив функции с двойными и целочисленными параметрами и целочисленным возвращаемым значением - код находится на pastebin (pastebin.com/pyUXf3RW) и (pastebin.com/0D700WPb). Однако я не знаю, где разместить функцию function.restype = c_double, чтобы вернуть двойное значение, чтобы не сказать, как передать параметр STL vector <vector <double>>, который является моей конечной потребностью.

Antonello 22.05.2014 17:45

Ссылка на ctypes в этом ответе не работает: docs.python.org/lib/module-ctypes.html

Anderson Green 04.06.2014 09:32

Не забудьте потом удалить указатель, например, предоставление функции Foo_delete и вызов ее либо из деструктора Python, либо упаковка объекта в ресурс.

Adversus 04.11.2015 11:34

Я получаю OSError: ./libfoo.so: undefined symbol: XGetImage, есть идеи, что может быть не так?

PascalVKooten 26.08.2017 12:34

Для компиляции dylib на Mac вам понадобится: g++ -dynamiclib -undefined suppress -flat_namespace *.o -o something.dylib, как: stackoverflow.com/questions/3532589/…

lkahtz 05.10.2017 06:01

У меня возникла ошибка -soname not found, поэтому я выполнил эту команду. "g ++ -fPIC -shared -o libfoo.so foo.o"

HaseeB Mir 18.05.2019 22:53

аналогичный пример / руководство с немного большей функциональностью: auctoris.co.uk/2017/04/29/…

Markus Dutschke 26.05.2020 16:13

В моей версии foo->bar() я получил segfault при доступе к переменной-члену класса (не в приведенном выше примере). В этом случае помогло добавление argtypes и restype. Смотрите здесь stackoverflow.com/questions/13754220/…

luopio 30.09.2020 11:10

Я думаю, что cffi для python может быть вариантом.

The goal is to call C code from Python. You should be able to do so without learning a 3rd language: every alternative requires you to learn their own language (Cython, SWIG) or API (ctypes). So we tried to assume that you know Python and C and minimize the extra bits of API that you need to learn.

http://cffi.readthedocs.org/en/release-0.7/

Я думаю, это может вызвать только c (не C++), но все же +1 (мне очень нравится cffi).

Andy Hayden 04.11.2014 06:01

Я начал свое путешествие в привязке Python <-> C++ с этой страницы с целью связать типы данных высокого уровня (многомерные векторы STL со списками Python) :-)

Попробовав решения, основанные как на ctypes, так и на boost.python (и не будучи инженером-программистом), я нашел их сложными, когда требуется привязка типов данных высокого уровня, в то время как я нашел SWIG намного более простым для таких случаев.

Поэтому в этом примере используется SWIG, и он был протестирован в Linux (но SWIG доступен и широко используется также в Windows).

Цель состоит в том, чтобы сделать функцию C++ доступной для Python, которая принимает матрицу в виде 2D-вектора STL и возвращает среднее значение каждой строки (как 1D-вектор STL).

Код на C++ ("code.cpp") выглядит следующим образом:

#include <vector>
#include "code.h"

using namespace std;

vector<double> average (vector< vector<double> > i_matrix) {

  // Compute average of each row..
  vector <double> averages;
  for (int r = 0; r < i_matrix.size(); r++){
    double rsum = 0.0;
    double ncols= i_matrix[r].size();
    for (int c = 0; c< i_matrix[r].size(); c++){
      rsum += i_matrix[r][c];
    }
    averages.push_back(rsum/ncols);
  }
  return averages;
}

Эквивалентный заголовок ("code.h"):

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

Сначала мы компилируем код C++ для создания объектного файла:

g++ -c -fPIC code.cpp

Затем мы определяем Файл определения интерфейса SWIG ("code.i") для наших функций C++.

%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {

  /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
  %template(VecDouble) vector<double>;
  %template(VecVecdouble) vector< vector<double> >;
}

%include "code.h"

Используя SWIG, мы генерируем исходный код интерфейса C++ из файла определения интерфейса SWIG.

swig -c++ -python code.i

Наконец, мы компилируем сгенерированный исходный файл интерфейса C++ и связываем все вместе, чтобы сгенерировать общую библиотеку, которая напрямую импортируется Python (значение "_"):

g++ -c -fPIC code_wrap.cxx  -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o

Теперь мы можем использовать функцию в скриптах Python:

#!/usr/bin/env python

import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b

Реальная реализация, где в коде C++ векторы stl передаются как неконстантные ссылки и, следовательно, доступны python в качестве выходных параметров: lobianco.org/antonello/personal:portfolio:portopt

Antonello 17.06.2014 11:46

Сначала вы должны решить, какова ваша конкретная цель. Официальная документация Python по расширение и встраивание интерпретатора Python упоминалась выше, я могу добавить хороший обзор бинарных расширений. Сценарии использования можно разделить на 3 категории:

  • модули ускорителей: чтобы работать быстрее, чем эквивалентный чистый код Python выполняется в CPython.
  • модули-обертки: предоставить существующие интерфейсы C коду Python.
  • доступ к системе низкого уровня: для доступа к функциям нижнего уровня среды выполнения CPython, операционной системы или базового оборудования.

Чтобы дать более широкую перспективу другим заинтересованным сторонам, и поскольку ваш первоначальный вопрос немного расплывчат («к библиотеке C или C++»), я думаю, что эта информация может быть вам интересна. По ссылке выше вы можете прочитать о недостатках использования двоичных расширений и их альтернативах.

Помимо других предложенных ответов, если вам нужен модуль ускорителя, вы можете попробовать Нумба. Он работает «путем генерации оптимизированного машинного кода с использованием инфраструктуры компилятора LLVM во время импорта, выполнения или статически (с использованием прилагаемого инструмента pycc)».

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

>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19

За подробным руководством вы можете обратиться к моя статья в блоге.

Возможно, стоит отметить, что, хотя ctypes переносимы, ваш код требует специфической для Windows библиотеки C.

Palec 28.08.2015 11:32

Cython определенно подходит, если вы не планируете писать оболочки Java, и в этом случае SWIG может быть предпочтительнее.

Я рекомендую использовать утилиту командной строки runcython, она делает процесс использования Cython чрезвычайно простым. Если вам нужно передать структурированные данные в C++, взгляните на библиотеку Google protobuf, это очень удобно.

Вот минимальный пример, который я сделал, в котором используются оба инструмента:

https://github.com/nicodjimenez/python2cpp

Надеюсь, это может быть полезной отправной точкой.

Существует также pybind11, который похож на облегченную версию Boost.Python и совместим со всеми современными компиляторами C++:

https://pybind11.readthedocs.io/en/latest/

Сегодня!! 2020 г. This should be the top answer! It is a template header only library. Many huge relevant projects recommends it, like Pytorchpytorch.org/tutorials/advanced/cpp_extension.html Also fully works on VS Community Windows
eusoubrasileiro 05.02.2020 15:41

Пожалуйста, также включите несколько примеров, чтобы сделать его более полезным, чем ответ только по ссылке.

Franklin Yu 17.07.2020 00:25

Это действительно выглядит потрясающе! жаль, что я только что нашел это. Я думаю, что для этого стоит переписать код.

LUser 01.08.2020 13:45

Я показал минимальный запускаемый пример по адресу: stackoverflow.com/a/60374990/895245, чтобы продемонстрировать, насколько это круто.

Ciro Santilli TRUMP BAN IS BAD 26.08.2020 14:26

Для современного C++ используйте cppyy: http://cppyy.readthedocs.io/en/latest/

Он основан на Cling, интерпретаторе C++ для Clang / LLVM. Привязки выполняются во время выполнения, и дополнительный промежуточный язык не требуется. Благодаря Clang он поддерживает C++ 17.

Установите его с помощью pip:

    $ pip install cppyy

Для небольших проектов просто загрузите соответствующую библиотеку и интересующие вас заголовки. возьмите код из примера ctypes - это этот поток, но разделенный на разделы заголовка и кода:

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

Скомпилируйте это:

    $ g++ -c -fPIC foo.cpp -o foo.o
    $ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so  foo.o

и используйте это:

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

Поддерживаются большие проекты с автоматической загрузкой подготовленной информации отражения и фрагментов cmake для их создания, так что пользователи установленных пакетов могут просто запускать:

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

Благодаря LLVM возможны расширенные функции, такие как автоматическое создание экземпляров шаблона. Чтобы продолжить пример:

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

Примечание: я автор cppyy.

На самом деле это не так: Cython - это Python-подобный язык программирования для написания модулей расширения C для Python (код Cython переводится на C вместе с необходимым шаблоном C-API). Он обеспечивает некоторую базовую поддержку C++. Программирование с помощью cppyy включает только Python и C++, без языковых расширений. Он полностью работает и не генерирует автономный код (ленивая генерация масштабируется намного лучше). Он нацелен на современный C++ (включая автоматические экземпляры шаблонов, перемещения, initializer_lists, лямбды и т. д. И т. Д.), А PyPy поддерживается изначально (т. Е. Не через медленный слой эмуляции C-API).

Wim Lavrijsen 22.04.2018 00:57

Этот Бумага PyHPC'16 содержит ряд значений тестов. Однако с тех пор на стороне CPython произошли определенные улучшения.

Wim Lavrijsen 12.06.2018 00:53

Мне нравится этот подход, потому что вам не нужно выполнять дополнительную работу по интеграции с swig, ctypes или boost.python. Вместо того, чтобы писать код, чтобы заставить python работать с вашим кодом на C++ ... python выполняет тяжелую работу, чтобы понять C++. Предполагая, что это действительно работает.

Trevor Boyd Smith 24.04.2019 23:30

cppyy очень интересно! Я вижу в документации, что происходит перераспределение и предварительная упаковка. Известно ли, что это хорошо работает с инструментами, которые также упаковывают код Python (например, PyInstaller)? Связано ли это с проектом ROOT или использовать его работу?

JimB 13.07.2019 02:29

Спасибо! Я не знаком с PyInstaller, но «словари», которые упаковывают предварительные объявления, пути и заголовки, представляют собой коды C++, скомпилированные в общие библиотеки. Поскольку cppyy используется для привязки кода C++, я полагаю, что обработка еще некоторого кода C++ должна быть в порядке. И этот код не зависит от Python C-API (только модуль libcppyy), что упрощает работу. Сам cppyy может быть установлен из conda-forge или pypi (pip), так что любая из этих сред наверняка будет работать. Да, cppyy начался как форк PyROOT, но с тех пор он настолько улучшился, что команда ROOT переустанавливает PyROOT поверх cppyy.

Wim Lavrijsen 14.07.2019 04:42

Мне нравится cppyy, он позволяет очень легко расширять Python с помощью кода C++, значительно повышая производительность, когда это необходимо.

Это мощный и, откровенно говоря, очень простой в использовании,

вот пример того, как вы можете создать массив numpy и передать его функции-члену класса в C++.

cppyy_test.py

import cppyy
import numpy as np
cppyy.include('Buffer.h')


s = cppyy.gbl.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)
print(numpy_array[:20])

Buffer.h

struct Buffer {
  void get_numpy_array(double *ad, int size) {
    for( long i=0; i < size; i++)
        ad[i]=i;
  }
};

Вы также можете очень легко создать модуль Python (с помощью CMake), таким образом вы избежите постоянной перекомпиляции кода C++.

Минимальный запускаемый пример pybind11

pybind11 ранее упоминался в https://stackoverflow.com/a/38542539/895245, но я хотел бы привести здесь конкретный пример использования и некоторое дальнейшее обсуждение реализации.

В общем, я настоятельно рекомендую pybind11, потому что он действительно прост в использовании: вы просто включаете заголовок, а затем pybind11 использует магию шаблона для проверки класса C++, который вы хотите предоставить Python, и делает это прозрачно.

Обратной стороной этой магии шаблона является то, что он замедляет компиляцию, сразу же добавляя несколько секунд к любому файлу, который использует pybind11, см., Например, расследование, проведенное по этому вопросу. PyTorch соглашается. Предложение по устранению этой проблемы было сделано по адресу: https://github.com/pybind/pybind11/pull/2445

Вот минимальный запускаемый пример, чтобы вы почувствовали, насколько хорош pybind11:

class_test.cpp

#include <string>

#include <pybind11/pybind11.h>

struct ClassTest {
    ClassTest(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }
    std::string name;
};

namespace py = pybind11;

PYBIND11_PLUGIN(class_test) {
    py::module m("my_module", "pybind11 example plugin");
    py::class_<ClassTest>(m, "ClassTest")
        .def(py::init<const std::string &>())
        .def("setName", &ClassTest::setName)
        .def("getName", &ClassTest::getName)
        .def_readwrite("name", &ClassTest::name);
    return m.ptr();
}

class_test_main.py

#!/usr/bin/env python3

import class_test

my_class_test = class_test.ClassTest("abc");
print(my_class_test.getName())
my_class_test.setName("012")
print(my_class_test.getName())
assert(my_class_test.getName() == my_class_test.name)

Скомпилируйте и запустите:

#!/usr/bin/env bash
set -eux
g++ `python3-config --cflags` -shared -std=c++11 -fPIC class_test.cpp \
  -o class_test`python3-config --extension-suffix` `python3-config --libs`
./class_test_main.py

В этом примере показано, как pybind11 позволяет легко предоставить класс ClassTest C++ для Python! Компиляция создает файл с именем class_test.cpython-36m-x86_64-linux-gnu.so, который class_test_main.py автоматически выбирает как точку определения для встроенного модуля class_test.

Возможно, осознание того, насколько это круто, осознано только в том случае, если вы попытаетесь сделать то же самое вручную с помощью собственного API Python, см., Например, этот пример этого, в котором примерно в 10 раз больше кода: https://github.com/cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c В этом примере вы можете увидеть как код C должен мучительно и явно определять класс Python по крупицам со всей содержащейся в нем информацией (члены, методы, дополнительные метаданные ...). Смотрите также:

pybind11 утверждает, что он похож на Boost.Python, который был упомянут в https://stackoverflow.com/a/145436/895245, но более минимален, потому что он свободен от раздувания внутри проекта Boost:

pybind11 is a lightweight header-only library that exposes C++ types in Python and vice versa, mainly to create Python bindings of existing C++ code. Its goals and syntax are similar to the excellent Boost.Python library by David Abrahams: to minimize boilerplate code in traditional extension modules by inferring type information using compile-time introspection.

The main issue with Boost.Python—and the reason for creating such a similar project—is Boost. Boost is an enormously large and complex suite of utility libraries that works with almost every C++ compiler in existence. This compatibility has its cost: arcane template tricks and workarounds are necessary to support the oldest and buggiest of compiler specimens. Now that C++11-compatible compilers are widely available, this heavy machinery has become an excessively large and unnecessary dependency.

Think of this library as a tiny self-contained version of Boost.Python with everything stripped away that isn't relevant for binding generation. Without comments, the core header files only require ~4K lines of code and depend on Python (2.7 or 3.x, or PyPy2.7 >= 5.7) and the C++ standard library. This compact implementation was possible thanks to some of the new C++11 language features (specifically: tuples, lambda functions and variadic templates). Since its creation, this library has grown beyond Boost.Python in many ways, leading to dramatically simpler binding code in many common situations.

pybind11 также является единственной альтернативой, не являющейся родной, на что указывает текущая документация по привязке Microsoft Python C по адресу: https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in-visual-studio?view=vs-2019 (архив).

Протестировано на Ubuntu 18.04, pybind11 2.0.1, Python 3.6.8, GCC 7.4.0.

Другие вопросы по теме