Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

General Techniques

Boost , Boost.Python Tutorial , Boost.Python Tutorial

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHome

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

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

Но мы обертываем код C++, используя Boost. Пайтон. Как мы можем предоставить хороший интерфейс пакета для наших пользователей? Чтобы лучше объяснить некоторые понятия, давайте поработаем с примером.

У нас есть библиотека C++, которая работает со звуками: чтение и написание различных форматов, применение фильтров к звуковым данным и т.д. Называется (удобно)Звуки. В нашей библиотеке уже есть аккуратная иерархия пространства имен C++:

sounds::core
sounds::io
sounds::filters

Мы хотели бы представить эту иерархию пользователю Python, позволив ему писать код следующим образом:

import sounds.filters
sounds.filters.echo(...) # echo is a C++ function

Первым шагом является написание кода упаковки. Мы должны экспортировать каждый модуль отдельно с Boost. Python, например:

/* file core.cpp */
BOOST_PYTHON_MODULE(core)
{
    /* export everything in the sounds::core namespace */
    ...
}
/* file io.cpp */
BOOST_PYTHON_MODULE(io)
{
    /* export everything in the sounds::io namespace */
    ...
}
/* file filters.cpp */
BOOST_PYTHON_MODULE(filters)
{
    /* export everything in the sounds::filters namespace */
    ...
}

Компиляция этих файлов будет генерировать следующие расширения Python:core.pyd,io.pydифильтры. пид.

[Note] Note

Расширение.pydиспользуется для модулей расширения Python, которые являются просто общими библиотеками. Использование по умолчанию для вашей системы, как.soдля Unix и.dllдля Windows, работает так же хорошо.

Теперь мы создаем эту структуру каталогов для нашего пакета Python:

sounds/
    __init__.py
    core.pyd
    filters.pyd
    io.pyd

Файл__init__.py— это то, что говорит Python, что каталогзвуков /на самом деле является пакетом Python. Это может быть пустой файл, но также может выполнять некоторую магию, которая будет показана позже.

Теперь наш пакет готов. Все, что пользователь должен сделать, это поместитьзвукив свойПИТОНПАТи запустить интерпретатор:

>>> import sounds.io
>>> import sounds.filters
>>> sound = sounds.io.open('file.mp3')
>>> new_sound = sounds.filters.echo(sound, 1.0)

Мило?

Это самый простой способ создания иерархий пакетов, но он не очень гибкий. Что делать, если мы хотим добавитьчистыйФункция Python для пакета фильтров, например, тот, который применяет 3 фильтра в звуковом объекте одновременно? Конечно, вы можете сделать это на C++ и экспортировать его, но почему бы не сделать это на Python? Вам не нужно перекомпилировать модули расширения, плюс его будет легче написать.

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

/* file core.cpp */
BOOST_PYTHON_MODULE(_core)
{
    ...
    /* export everything in the sounds::core namespace */
}

Обратите внимание, что мы добавили подчеркивание к названию модуля. Имя файла также должно быть изменено на_core.pyd, и мы делаем то же самое с другими модулями расширения. Теперь мы меняем иерархию пакетов так:

sounds/
    __init__.py
    core/
        __init__.py
        _core.pyd
    filters/
        __init__.py
        _filters.pyd
    io/
        __init__.py
        _io.pyd

Обратите внимание, что мы создали каталог для каждого модуля расширения и добавили __init__.py к каждому из них. Но если мы оставим это так, пользователю придется получить доступ к функциям в базовом модуле с этим синтаксисом:

>>> import sounds.core._core
>>> sounds.core._core.foo(...)

Это не то, чего мы хотим. Но здесь вводится магия__init__.py: все, что привнесено в пространство имен__init__.py, может быть доступно непосредственно пользователю. Итак, все, что нам нужно сделать, это перенести все пространство имен из_core.pydвcore/__init__py. Так что добавьте эту строку кода кSounds/core/__init__.py:

from _core import *

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

>>> import sounds.filters
>>> sounds.filters.echo(...)

С дополнительным преимуществом, что мы можем легко добавить чистые функции Python в любой модуль, таким образом, что пользователь не может отличить функцию C++ от функции Python. ДобавимчистыйФункция Python,эхо_шум, в пакетфильтров. Эта функция применяется какэхо, так ишумфильтров в последовательности в данномзвукеобъекте. Мы создаем файл под названиемsounds/filters/echo_noise.pyи кодируем нашу функцию:

import _filters
def echo_noise(sound):
    s = _filters.echo(sound)
    s = _filters.noise(sound)
    return s

Далее мы добавим эту строку вSounds/filters/__init__.py:

from echo_noise import echo_noise

Вот и все. Теперь пользователь получает доступ к этой функции, как и к любой другой функции из пакетафильтров:

>>> import sounds.filters
>>> sounds.filters.echo_noise(...)

Благодаря гибкости Python можно легко добавлять новые методы в класс, даже после того, как он уже был создан:

>>> class C(object): pass
>>>
>>> # a regular function
>>> def C_str(self): return 'A C instance!'
>>>
>>> # now we turn it in a member function
>>> C.__str__ = C_str
>>>
>>> c = C()
>>> print c
A C instance!
>>> C_str(c)
A C instance!

Да, Python rox.

Мы можем сделать то же самое с классами, которые были завернуты в Boost. Пайтон. Предположим, что у нас есть классточкана C++:

class point {...};
BOOST_PYTHON_MODULE(_geom)
{
    class_<point>("point")...;
}

Если мы используем технику из предыдущей сессииСоздание пакетов, мы можем кодировать непосредственно вgeom/__init__.py:

from _geom import *
# a regular function
def point_str(self):
    return str((self.x, self.y))
# now we turn it into a member function
point.__str__ = point_str

Всеточечные экземпляры, созданные на C++, также будут иметь эту функцию участника! Эта техника имеет несколько преимуществ:

  • Сократите время компиляции до нуля для этих дополнительных функций.
  • Уменьшить объем памяти практически до нуля
  • Минимизируйте необходимость рекомпилирования
  • Быстрое прототипирование (при необходимости можно переместить код на C++ без изменения интерфейса)

Можно даже добавить немного синтаксического сахара с помощью метаклассов. Создадим специальный метакласс, который «впрыскивает» методы в другие классы.

# The one Boost.Python uses for all wrapped classes.
# You can use here any class exported by Boost instead of "point"
BoostPythonMetaclass = point.__class__
class injector(object):
    class __metaclass__(BoostPythonMetaclass):
        def __init__(self, name, bases, dict):
            for b in bases:
                if type(b) not in (self, type):
                    for k,v in dict.items():
                        setattr(b,k,v)
            return type.__init__(self, name, bases, dict)
# inject some methods in the point foo
class more_point(injector, point):
    def __repr__(self):
        return 'Point(x=%s, y=%s)' % (self.x, self.y)
    def foo(self):
        print 'foo!'

Теперь посмотрим, как это получилось:

>>> print point()
Point(x=10, y=10)
>>> point().foo()
foo!

Еще одна полезная идея заключается в замене конструкторов заводскими функциями:

_point = point
def point(x=0, y=0):
    return _point(x, y)

В этом простом случае мало что получается, но для конструкторов с большим количеством перегрузок и / или аргументов это часто большое упрощение, опять же с практически нулевым объемом памяти и нулевыми затратами времени компиляции для поддержки ключевых слов.

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

/* file point.cpp */
#include <point.h>
#include <boost/python.hpp>
void export_point()
{
    class_<point>("point")...;
}
/* file triangle.cpp */
#include <triangle.h>
#include <boost/python.hpp>
void export_triangle()
{
    class_<triangle>("triangle")...;
}

Теперь вы создаете файлmain.cpp, который содержит макросBOOST_PYTHON_MODULE, и вызываете различные функции экспорта внутри него.

void export_point();
void export_triangle();
BOOST_PYTHON_MODULE(_geom)
{
    export_point();
    export_triangle();
}

Сбор и объединение всех этих файлов дает тот же результат, что и обычный подход:

#include <boost/python.hpp>
#include <point.h>
#include <triangle.h>
BOOST_PYTHON_MODULE(_geom)
{
    class_<point>("point")...;
    class_<triangle>("triangle")...;
}

Но память держится под контролем.

Этот метод также рекомендуется, если вы разрабатываете библиотеку C++ и одновременно экспортируете ее на Python: изменения в классе потребуют только компиляции одного cpp вместо всего кода обертки.

[Note] Note

Этот метод также полезен, если вы получаете сообщение об ошибке«фатальная ошибка C1204:Предел компилятора: переполнение внутренней структуры»при компиляции большого исходного файла, как объясняется вFAQ.


PrevUpHome

Статья General Techniques раздела Boost.Python Tutorial Boost.Python Tutorial может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Boost.Python Tutorial ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 18:16:39/0.0087759494781494/0