![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Building Hybrid Systems with Boost.PythonBoost , ,
|
Author: | Давид Абрахамс | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Contact: | Повышаю. Python - это библиотека C++ с открытым исходным кодом, которая предоставляет краткий IDL-подобный интерфейс для связывания классов и функций C++ с Python. Используя всю мощь интроспекции времени компиляции C++ и недавно разработанных методов метапрограммирования, это достигается полностью в чистом C++, без введения нового синтаксиса. Повышаю. Богатый набор функций Python и высокоуровневый интерфейс позволяют создавать пакеты с нуля в виде гибридных систем, предоставляя программистам легкий и последовательный доступ как к эффективному полиморфизму C++, так и к чрезвычайно удобному полиморфизму Python.
IntroductionPython и C++ во многом отличаются друг от друга: в то время как C++ обычно компилируется в машинный код, Python интерпретируется. Система динамического типа Python часто упоминается как основа ее гибкости, в то время как статическая типизация на C++ является краеугольным камнем ее эффективности. C++ имеет сложный и сложный метаязык времени компиляции, в то время как в Python практически все происходит во время выполнения. Однако для многих программистов эти различия означают, что Python и C++ прекрасно дополняют друг друга. Узкие места производительности в программах Python могут быть переписаны на C++ для максимальной скорости, и авторы мощных библиотек C++ выбирают Python в качестве промежуточного языка для своих гибких возможностей системной интеграции. Кроме того, поверхностные различия маскируют некоторые сильные сходства:
Учитывая богатый API совместимости «C» Python, в принципе должно быть возможно подвергнуть интерфейсы типа и функции C++ Python с аналогичным интерфейсом для их аналогов C++. Однако возможности, предоставляемые только Python для интеграции с C++, относительно скудны. По сравнению с C++ и Python, C имеет только очень элементарные средства абстракции, и поддержка обработки исключений полностью отсутствует. Создатели модулей расширения «C» должны вручную управлять количеством ссылок на Python, что раздражающе утомительно и чрезвычайно подвержено ошибкам. Традиционные модули расширения также, как правило, содержат много повторения кода, что затрудняет их обслуживание, особенно при обертке развивающегося API. Эти ограничения привели к разработке различных систем упаковки. SWIG, пожалуй, самый популярный пакет для интеграции C/C++ и Python. Более поздней разработкой является SIP, который был специально разработан для взаимодействия Python с графической библиотекой пользовательского интерфейса Qt. Как SWIG, так и SIP представляют свои собственные специализированные языки для настройки межъязыковых связей. Это имеет определенные преимущества, но при работе с тремя различными языками (Python, C/C++ и язык интерфейса) также возникают практические и умственные трудности. Пакет CXX демонстрирует интересную альтернативу. Это показывает, что, по крайней мере, некоторые части API Python 'C' могут быть обернуты и представлены через гораздо более удобный интерфейс C++. Однако, в отличие от SWIG и SIP, CXX не включает поддержку обертывания классов C++ в новые типы Python. Функции и цели Boost.Python значительно совпадают со многими из этих других систем. Вот так, буст. Python стремится максимизировать удобство и гибкость без введения отдельного языка обертывания. Вместо этого он предоставляет пользователю высокоуровневый интерфейс C++ для обертывания классов и функций C++, управляя большей частью сложности за кулисами со статическим метапрограммированием. Повышаю. Python также выходит за рамки более ранних систем, предоставляя:
Ключевое понимание, которое вызвало развитие Boost. Python заключается в том, что большая часть кода boilerplate в традиционных модулях расширения может быть устранена с помощью интроспекции времени компиляции C++. Каждый аргумент обернутой функции C++ должен быть извлечен из объекта Python с помощью процедуры, которая зависит от типа аргумента. Точно так же тип возврата функции определяет, как значение возврата будет преобразовано из C++ в Python. Конечно, типы аргументов и возвратов являются частью типа каждой функции, и это именно тот источник, из которого Boost. Python выводит большую часть необходимой информации. Этот подход приводит к пользовательской обертке : как можно больше информации извлекается непосредственно из исходного кода для обертывания в рамках чистого C++, а некоторая дополнительная информация предоставляется явно пользователем. В основном руководство является механическим, и требуется мало реального вмешательства. Поскольку спецификация интерфейса написана на том же полнофункциональном языке, что и раскрытый код, пользователь имеет беспрецедентную мощность, доступную, когда ему нужно взять под контроль. Boost.Python Design GoalsОсновная цель Boost. Python позволяет пользователям открывать классы и функции C++ для Python, используя только компилятор C++. В общих чертах, пользовательский опыт должен быть одним из непосредственных манипуляций объектами C++ с Python. Однако также важно не переводить все интерфейсы too буквально: идиомы каждого языка должны уважаться. Например, хотя C++ и Python имеют концепцию итератора, они выражаются по-разному. Повышаю. Python должен быть в состоянии преодолеть разрыв в интерфейсе. Должна быть возможность изолировать пользователей Python от сбоев в результате тривиальных злоупотреблений интерфейсами C++, таких как доступ к уже удаленным объектам. Таким же образом библиотека должна изолировать пользователей C++ от низкоуровневого API Python 'C', заменяя подверженные ошибкам интерфейсы 'C', такие как ручное управление ссылочным счетом и необработанные указатели PyObject более надежными альтернативами. Поддержка разработки на основе компонентов имеет решающее значение, поэтому типы C++, представленные в одном модуле расширения, могут быть переданы функциям, раскрытым в другом, без потери важной информации, такой как отношения наследования C++. Наконец, вся обертка должна быть ненавязчивой , без изменения или даже просмотра исходного кода C++. Существующие библиотеки C++ должны быть доступны третьим лицам, которые имеют доступ только к файлам заголовков и двоичным файлам. Hello Boost.Python WorldА теперь предисловие к Boost. Python, и как он улучшает исходные возможности, предлагаемые Python. Вот функция, которую мы можем разоблачить: char const* greet(unsigned x) { static char const* const msgs[] = { "hello", "Boost.Python", "world!" }; if (x > 2) throw std::range_error("greet: index out of range"); return msgs[x]; } Чтобы обернуть эту функцию в стандартный C++ с помощью API Python 'C', нам нужно что-то вроде этого: extern "C" // all Python interactions use 'C' linkage and calling convention { // Wrapper to handle argument/result conversion and checking PyObject* greet_wrap(PyObject* args, PyObject * keywords) { int x; if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments { char const* result = greet(x); // invoke wrapped function return PyString_FromString(result); // convert result to Python } return 0; // error occurred } // Table of wrapped functions to be exposed by the module static PyMethodDef methods[] = { { "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" } , { NULL, NULL, 0, NULL } // sentinel }; // module initialization function DL_EXPORT init_hello() { (void) Py_InitModule("hello", methods); // add the methods to the module } } Вот код упаковки, который мы используем, чтобы разоблачить его с помощью Boost. Python: #include <boost/python.hpp> using namespace boost::python; BOOST_PYTHON_MODULE(hello) { def("greet", greet, "return one of 3 parts of a greeting"); } и вот он в действии: >>> import hello >>> for x in range(3): ... print hello.greet(x) ... hello Boost.Python world! Помимо того, что версия API C гораздо более многословна, стоит отметить несколько вещей, с которыми она не справляется правильно:
Library OverviewВ этом разделе описываются некоторые из основных функций библиотеки. За исключением необходимости избежать путаницы, детали реализации библиотеки опущены. Exposing ClassesКлассы и структуры C++ выставляются с аналогичным интерфейсом. Учитывая: struct World { void set(std::string msg) { this->msg = msg; } std::string greet() { return msg; } std::string msg; }; Следующий код будет отображать его в нашем модуле расширения: #include <boost/python.hpp> BOOST_PYTHON_MODULE(hello) { class_<World>("World") .def("greet", &World::greet) .def("set", &World::set) ; } Несмотря на то, что этот код имеет определенную питоничность, люди иногда находят синтаксический бит запутанным, потому что он не похож на большую часть кода C++, к которому они привыкли. Но это только стандартный C++. Из-за их гибкого синтаксиса и перегрузки оператора C++ и Python отлично подходят для определения доменных языков (DSL), и это то, что мы сделали в Boost. Пайтон. Чтобы разбить его: class_<World>("World") конструирует неназванный объект типа class_ class_<World> w("World"); но это было бы более многословно, так как нам пришлось бы снова назвать w, чтобы вызвать его функцию члена def(): w.def("greet", &World::greet) В оригинальном примере нет ничего особенного в расположении точки для доступа к членам: C++ допускает любое количество белого пространства по обе стороны токена, а размещение точки в начале каждой строки позволяет нам цеплять столько последовательных вызовов к функциям-членам, сколько нам нравится, с однородным синтаксисом. Другой ключевой факт, который позволяет цепочку, заключается в том, что функции class_<> возвращают ссылку на *this. Таким образом, пример эквивалентен: class_<World> w("World"); w.def("greet", &World::greet); w.def("set", &World::set); Иногда полезно иметь возможность расщеплять компоненты Роста. Обертка класса Python таким образом, но остальная часть этой статьи будет придерживаться синтаксиса. Для полноты, вот завернутый класс в использовании: >>> import hello >>> planet = hello.World() >>> planet.set('howdy') >>> planet.greet() 'howdy' ConstructorsПоскольку наш класс World является простым struct, он имеет неявный конструктор без аргументов. Повышаю. Python по умолчанию раскрывает нулевой конструктор, поэтому мы смогли написать: >>> planet = hello.World() Однако хорошо разработанные классы на любом языке могут потребовать аргументов конструктора для установления их инвариантов. В отличие от Python, где _init__ является только специально названным методом, в C++ конструкторы не могут обрабатываться как обычные функции-члены. В частности, мы не можем взять их адрес: &World::World является ошибкой. Библиотека предоставляет другой интерфейс для определения конструкторов. Учитывая: struct World { World(std::string msg); // added constructor ... мы можем изменить наш код упаковки следующим образом: class_<World>("World", init<std::string>()) ... конечно, класс C++ может иметь дополнительные конструкторы, и мы можем разоблачить их, передав больше экземпляров init<...> def(): class_<World>("World", init<std::string>()) .def(init<double, double>()) ... Повышаю. Python позволяет перегружать обернутые функции, функции-члены и конструкторы, чтобы отразить перегрузку C++. Data Members and PropertiesЛюбые общедоступные члены данных в классе C++ могут быть легко представлены как атрибуты readonly или readwrite: class_<World>("World", init<std::string>()) .def_readonly("msg", &World::msg) ... можно использовать непосредственно в Python: >>> planet = hello.World('howdy') >>> planet.msg 'howdy' Это приводит к добавлению атрибутов в экземпляр World _dict__, что может привести к значительной экономии памяти при обертывании больших структур данных. Фактически, ни один экземпляр _dict__ не будет создан, если атрибуты явно не добавлены из Python. Повышаю. Python обязан этой возможностью новой системе типа Python 2.2, в частности интерфейсу дескриптора и свойству Тип. В C++ общедоступные данные считаются признаком плохого дизайна, потому что они нарушают инкапсуляцию, а руководства по стилю обычно диктуют использование функций "getter" и "setter". Однако в Python _getattr__, _setattr__ и, начиная с 2.2, property означают, что доступ к атрибутам является еще одним хорошо инкапсулированным синтаксическим инструментом в распоряжении программиста. Повышаю. Python устраняет этот идиоматический разрыв, делая создание Python property доступным для пользователей. Если бы msg был приватным, мы все равно могли бы раскрыть его как атрибут в Python следующим образом: class_<World>("World", init<std::string>()) .add_property("msg", &World::greet, &World::set) ... Приведенный выше пример отражает привычное использование свойств в Python 2.2+: >>> class World(object): ... __init__(self, msg): ... self.__msg = msg ... def greet(self): ... return self.__msg ... def set(self, msg): ... self.__msg = msg ... msg = property(greet, set) Operator OverloadingВозможность писать арифметические операторы для определяемых пользователем типов была основным фактором успеха обоих языков для численных вычислений, а успех пакетов, таких как NumPy, свидетельствует о силе воздействия операторов в модулях расширения. Повышаю. Python предоставляет лаконичный механизм для перегрузок оператора обертки. Приведенный ниже пример показывает фрагмент из обертки для библиотеки рациональных чисел Boost: class_<rational<int> >("rational_int") .def(init<int, int>()) // constructor, e.g. rational_int(3,4) .def("numerator", &rational<int>::numerator) .def("denominator", &rational<int>::denominator) .def(-self) // __neg__ (unary minus) .def(self + self) // __add__ (homogeneous) .def(self * self) // __mul__ .def(self + int()) // __add__ (heterogenous) .def(int() + self) // __radd__ ... Магия выполняется с помощью упрощенного применения шаблонов "экспрессии" [VELD1995], методики, первоначально разработанной для оптимизации высокопроизводительных матричных алгебр. Суть в том, что вместо немедленного выполнения вычисления операторы перегружены для построения типа , представляющего вычисления. В матричной алгебре часто доступны драматические оптимизации, когда можно принять во внимание структуру целого выражения, а не оценивать каждую операцию. Повышаю. Python использует ту же технику для построения соответствующего объекта метода Python на основе выражений, включающих self. InheritanceНаследственные отношения C++ могут быть представлены на Boost. Python, добавив дополнительный аргумент bases<...> в список параметров шаблона class_<...> следующим образом: class_<Derived, bases<Base1,Base2> >("Derived") ... Это имеет два эффекта:
Конечно, можно получить новые классы Python из завернутых экземпляров класса C++. Потому что буст. Python использует новую систему классов, которая работает так же, как и для встроенных типов Python. Существует одна существенная деталь, в которой она отличается: встроенные типы обычно устанавливают свои инварианты в своей функции _new__, так что производным классам не нужно вызывать _init__ на базовый класс, прежде чем ссылаться на его методы: >>> class L(list): ... def __init__(self): ... pass ... >>> L().reverse() >>> Поскольку построение объекта C++ является одноэтапной операцией, данные экземпляра C++ не могут быть построены до тех пор, пока не будут доступны аргументы в функции __init__: >>> class D(SomeBoostPythonClass): ... def __init__(self): ... pass ... >>> D().some_boost_python_method() Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: bad argument type for built-in operation Это произошло из-за повышения. Python не смог найти данные экземпляров типа SomeBoostPythonClass в экземпляре D; D в функции _init__ маскировали конструкцию базового класса. Его можно исправить, удалив функцию D _init__ или назвав ее SomeBoostPythonClass.__init__(...) явно. Virtual FunctionsПолучение новых типов в Python из классов расширений не очень интересно, если они не могут быть использованы полиморфно из C++. Другими словами, реализация метода Python должна, по-видимому, переопределять реализацию виртуальных функций C++ при вызове через указатели базового класса / ссылки из C++. Поскольку единственный способ изменить поведение виртуальной функции состоит в том, чтобы переопределить ее в производном классе, пользователь должен построить специальный производный класс для отправки виртуальных функций полиморфного класса: // // interface to wrap: // class Base { public: virtual int f(std::string x) { return 42; } virtual ~Base(); }; int calls_f(Base const& b, std::string x) { return b.f(x); } // // Wrapping Code // // Dispatcher class struct BaseWrap : Base { // Store a pointer to the Python object BaseWrap(PyObject* self_) : self(self_) {} PyObject* self; // Default implementation, for when f is not overridden int f_default(std::string x) { return this->Base::f(x); } // Dispatch implementation int f(std::string x) { return call_method<int>(self, "f", x); } }; ... def("calls_f", calls_f); class_<Base, BaseWrap>("Base") .def("f", &Base::f, &BaseWrap::f_default) ; Вот код Python, который демонстрирует: >>> class Derived(Base): ... def f(self, s): ... return len(s) ... >>> calls_f(Base(), 'foo') 42 >>> calls_f(Derived(), 'forty-two') 9 Что нужно знать о классе диспетчера:
Deeper Reflection on the Horizon?По общему признанию, эту формулу утомительно повторять, особенно на проекте со многими полиморфными классами. То, что это необходимо, отражает некоторые ограничения в возможностях интроспекции компиляции C++: нет способа перечислить членов класса и выяснить, какие из них являются виртуальными функциями. По крайней мере, один очень перспективный проект был начат для создания интерфейса, который может автоматически генерировать эти диспетчеры (и другой код упаковки) из заголовков C++. Pyste разрабатывает Бруно да Силва де Оливейра. Он основан на GCC_XML, который генерирует XML-версию внутреннего представления программы GCC. Поскольку GCC является высококонформным компилятором C++, это обеспечивает правильную обработку самого сложного шаблонного кода и полный доступ к базовой системе типов. В соответствии с повышением. Философия Python, описание интерфейса Pyste не является ни навязчивым в коде, ни выраженным на каком-то незнакомом языке: вместо этого это 100% чистый скрипт Python. Если Pyste добьется успеха, для многих наших пользователей это будет означать отход от непосредственной упаковки всего на C++. Это также позволит нам перенести часть метапрограммного кода с C++ на Python. Мы ожидаем, что в ближайшее время не только наши пользователи, но и рост. Сами разработчики Python будут думать о гибридном коде. SerializationСериализация представляет собой процесс преобразования объектов в памяти в форму, которая может храниться на диске или передаваться по сетевому соединению. Серийный объект (чаще всего простая строка) может быть извлечен и преобразован обратно в исходный объект. Хорошая система сериализации автоматически преобразует целые иерархии объектов. Стандартный модуль Python pickle является именно такой системой. Он использует сильные средства интроспекции среды выполнения языка для сериализации практически произвольных пользовательских объектов. С несколькими простыми и ненавязчивыми положениями этот мощный механизм может быть расширен для работы с обернутыми объектами C++. Вот пример: #include <string> struct World { World(std::string a_msg) : msg(a_msg) {} std::string greet() const { return msg; } std::string msg; }; #include <boost/python.hpp> using namespace boost::python; struct World_picklers : pickle_suite { static tuple getinitargs(World const& w) { return make_tuple(w.greet()); } }; BOOST_PYTHON_MODULE(hello) { class_<World>("World", init<std::string>()) .def("greet", &World::greet) .def_pickle(World_picklers()) ; } Теперь давайте создадим объект World и положим его на диск: >>> import hello >>> import pickle >>> a_world = hello.World("howdy") >>> pickle.dump(a_world, open("my_world", "w")) В потенциально отличном сценарии на потенциально отличном компьютере с потенциально отличной операционной системой : >>> import pickle >>> resurrected_world = pickle.load(open("my_world", "r")) >>> resurrected_world.greet() 'howdy' Конечно, модуль cPickle также может использоваться для более быстрой обработки. Boost.Python's pickle_suite полностью поддерживает протокол pickle, определенный в стандартной документации Python. Как и функция __getinitargs__ в Python, getinitargs() pickle_suite отвечает за создание набора аргументов, который будет использоваться для реконструкции маринованного объекта. Другие элементы протокола пиклинга Python, __getstate__ и __setstate__, могут быть предоставлены с помощью функций getstate и setstate на C++. Система статического типа C++ позволяет библиотеке гарантировать, что бессмысленные комбинации функций (например, getstate без setstate) не используются. Возможность сериализации более сложных объектов C++ требует немного больше работы, чем показано в примере выше. К счастью, интерфейс object (см. следующий раздел) значительно помогает поддерживать управляемость кода. Object interfaceОпытный Авторы модуля расширения языка «C» будут знакомы с вездесущим PyObject*, ручным подсчетом ссылок и необходимостью помнить, какой API вызывает возврат "новые" (принадлежащие) ссылки или "заимствованные" (сырые) ссылки. Эти ограничения не только громоздки, но и являются основным источником ошибок, особенно при наличии исключений. Повышаю. Python предоставляет класс объект , который автоматизирует подсчет ссылок и обеспечивает преобразование в Python из объектов C++ произвольного типа. Это значительно снижает усилия по обучению потенциальных авторов модулей расширения. Создать объект из любого другого типа очень просто: object s("hello, world"); // s manages a Python string object имеет шаблонные взаимодействия со всеми другими типами, с автоматическими преобразованиями в Python. Это происходит настолько естественно, что легко упускается из виду: object ten_Os = 10 * s[4]; // -> "oooooooooo" В приведенном выше примере 4 и 10 преобразуются в объекты Python перед вызовом операций индексирования и умножения. Шаблон класса extract double x = extract<double>(o); Если преобразование в любом направлении не может быть выполнено, соответствующее исключение выбрасывается во время выполнения. Тип object сопровождается набором производных типов, которые максимально отражают встроенные типы Python, такие как list, dict, tuple и т.д. Это позволяет удобно манипулировать этими высокоуровневыми типами из C++: dict d; d["some"] = "thing"; d["lucky_number"] = 13; list l = d.keys(); Это выглядит и работает как обычный код Python, но это чистый C++. Конечно, мы можем обернуть функции C++, которые принимают или возвращают экземпляры object. Thinking hybridИз-за практических и умственных трудностей, связанных с объединением языков программирования, в начале любого процесса разработки принято урегулировать один язык. Для многих приложений соображения производительности диктуют использование компилируемого языка для основных алгоритмов. К сожалению, из-за сложности системы статического типа цена, которую мы платим за производительность во время выполнения, часто значительно увеличивает время разработки. Опыт показывает, что написание поддерживаемого кода C++ обычно занимает больше времени и требует далеко больше заработанного опыта работы, чем разработка сопоставимого кода Python. Даже когда разработчикам удобно работать исключительно на компилируемых языках, они часто дополняют свои системы каким-то специальным сценарным слоем в интересах своих пользователей, никогда не пользуясь теми же преимуществами. Повышаю. Python позволяет нам думать о гибриде . Python может быть использован для быстрого прототипирования нового приложения; его простота использования и большой пул стандартных библиотек дают нам преимущество на пути к рабочей системе. При необходимости рабочий код может быть использован для обнаружения горячих точек, ограничивающих скорость. Чтобы максимизировать производительность, они могут быть реализованы на C++ вместе с Boost. Привязка к Python необходима, чтобы связать их с существующей процедурой более высокого уровня. Конечно, этот подход top-down менее привлекателен, если с самого начала ясно, что многие алгоритмы в конечном итоге должны быть реализованы на C++. К счастью, рост. Python также позволяет использовать подход bottom-up. Мы очень успешно использовали этот подход при разработке инструментария для научных применений. Инструментарий начинался в основном как библиотека классов C++ с Boost. Привязка Python, и некоторое время рост был в основном сосредоточен на C++ частях. Однако по мере того, как набор инструментов становится все более полным, все больше и больше новых функций могут быть реализованы в Python. ![]() Эта цифра показывает предполагаемое соотношение недавно добавленного кода C++ и Python с течением времени по мере внедрения новых алгоритмов. Мы ожидаем, что это соотношение выровняется около 70% Python. Возможность решать новые задачи в основном на Python, а не на более сложном статически типизированном языке, является возвратом наших инвестиций в Boost. Возможность доступа ко всему нашему коду с Python позволяет более широкой группе разработчиков использовать его в быстрой разработке новых приложений. Development historyПервая версия Boost. Python был разработан в 2000 году Дэйвом Абрахамсом в Dragon Systems, где он получил привилегию иметь Тима Питерса в качестве руководства к «Дзену Python». Одной из задач Дэйва была разработка системы обработки естественного языка на основе Python. Поскольку он в конечном итоге предназначался для встроенного оборудования, всегда предполагалось, что вычислительное ядро будет переписано на C++ для оптимизации скорости и объема памяти 1. Проект также хотел протестировать весь свой код C++ с помощью тестовых скриптов Python2. Единственный инструмент, который мы знали для связывания C++ и Python, был SWIG, и в то время его обработка C++ была слабой. Было бы неверно утверждать о каком-либо глубоком понимании возможных преимуществ Boost. Подход Python на данном этапе. Интерес и опыт Дейва в причудливых шаблонных трюках на C++ только что достигли точки, когда он мог нанести реальный ущерб. Python появился так же, как и раньше, потому что он заполнил потребность и казался классной вещью. Эта ранняя версия была направлена на многие из тех же основных целей, которые мы описали в этой статье, отличаясь наиболее заметно наличием немного более громоздкого синтаксиса и отсутствием специальной поддержки для перегрузки оператора, маринования и разработки на основе компонентов. Эти последние три функции были быстро добавлены Ullrich Koethe и Ralf Grosse-Kunstleve3, и другие восторженные участники прибыли на сцену, чтобы внести улучшения, такие как поддержка вложенных модулей и статических функций участников. К началу 2001 года разработка стабилизировалась, и было добавлено мало новых функций, но появился новый тревожный факт: Ральф начал тестирование Boost. Python на предрелизных версиях компилятора с использованием интерфейса EDG и механизма в ядре Boost. Python, ответственный за обработку конверсий между типами Python и C++, не компилировался. Как оказалось, мы использовали очень распространенную ошибку в реализации всех C++-компиляторов, которые мы тестировали. Мы знали, что по мере того, как компиляторы C++ быстро становились более совместимыми со стандартами, библиотека начинала выходить из строя на большем количестве платформ. К сожалению, из-за того, что механизм был настолько центральным для функционирования библиотеки, решить проблему было очень сложно. К счастью, в том же году Лоуренс Беркли и Лоуренс Ливермор заключили контракт с Boost Consulting для поддержки и развития Boost. Python, и появилась новая возможность для решения фундаментальных вопросов и обеспечения будущего библиотеки. Усилия по редизайну начались с архитектуры преобразования типа низкого уровня, построение в соответствии со стандартами и поддержка разработки на основе компонентов (в отличие от версии 1, где преобразования должны были быть явно импортированы и экспортированы через границы модулей). Был проведен новый анализ взаимосвязи между объектами Python и C++, что привело к более интуитивной обработке значений C++ lvalues и rvalues. Появление мощной системы нового типа в Python 2.2 сделало выбор между поддержанием совместимости с Python 1.5.2 простым: возможность выбросить много сложного кода для эмуляции классических классов Python была слишком хороша, чтобы упустить ее. Кроме того, итераторы и дескрипторы Python предоставили важные и элегантные инструменты для представления аналогичных конструкций C++. Разработка обобщенного интерфейса object позволила дополнительно защитить программистов C++ от опасностей и синтаксического бремени API Python 'C'. В этот период было добавлено множество других функций, включая перевод исключений на C++, улучшенную поддержку перегруженных функций и, самое главное, CallPolicies для обработки указателей и ссылок. В октябре 2002 года вышла версия 2 Boost. Python был выпущен. С тех пор разработка была сосредоточена на улучшенной поддержке полиморфизма времени выполнения C++ и интеллектуальных указателей. Гениальный дизайн Питера Димова boost::shared_ptr, в частности, позволил нам предоставить гибридному разработчику последовательный интерфейс для перемещения объектов туда и обратно через языковой барьер без потери информации. Сначала мы были обеспокоены изощренностью и сложностью Boost. Реализация Python v2 может отпугнуть участников, но появление Pyste и нескольких других важных функций положило конец этим опасениям. Ежедневные вопросы по Python C++-sig и отставание от желаемых улучшений показывают, что библиотека начинает использоваться. Для нас будущее выглядит светлым. ConclusionsПовышаю. Python обеспечивает бесшовную совместимость между двумя богатыми и бесплатными языковыми средами. Поскольку он использует метапрограммирование шаблонов для интроспективы типов и функций, пользователю никогда не нужно изучать третий синтаксис: определения интерфейса написаны сжатым и поддерживаемым C++. Кроме того, оберточная система не должна анализировать заголовки C++ или представлять систему типов: компилятор делает эту работу за нас. Вычислительно интенсивные задачи играют на сильных сторонах C++ и часто невозможно эффективно реализовать в чистом Python, в то время как такие задачи, как сериализация, которые являются тривиальными в Python, могут быть очень сложными в чистом C++. Учитывая роскошь создания гибридной программной системы с нуля, мы можем подойти к дизайну с новой уверенностью и силой. Citations
Footnotes
Статья Building Hybrid Systems with Boost.Python раздела может быть полезна для разработчиков на c++ и boost. Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта. :: Главная :: ::
|
|||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |