![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
General TechniquesBoost , Boost.Python Tutorial , Boost.Python Tutorial
|
![]() |
Note |
---|---|
Расширение |
Теперь мы создаем эту структуру каталогов для нашего пакета 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++, также будут иметь эту функцию участника! Эта техника имеет несколько преимуществ:
Можно даже добавить немного синтаксического сахара с помощью метаклассов. Создадим специальный метакласс, который «впрыскивает» методы в другие классы.
# 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 |
---|---|
Этот метод также полезен, если вы получаете сообщение об ошибке«фатальная ошибка C1204:Предел компилятора: переполнение внутренней структуры»при компиляции большого исходного файла, как объясняется вFAQ. |
Статья General Techniques раздела Boost.Python Tutorial Boost.Python Tutorial может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Boost.Python Tutorial ::
реклама |