SlideShare a Scribd company logo
Boost.Python 
C++ & Python Integration
Motivation 
Leveraging of strong sides in both languages: 
1. C++: 
a. performance, 
b. effective resource management 
2. Python: 
a. high coding performance, 
b. variety of available solutions 
c. easy to start
Why Boost.Python? 
Python C-API: requires too much manual work 
SWIG (aka generators): usually requires 
manual adjusting - take time to understand 
“someones” code. 
Boost.Python (middleware lib): most flexible - 
expose what you need in the way you like.
Getting Boost ready 
Getting Boost ready: 
get your copy of boost and build it: 
./bootstrap.sh --prefix=../../ --with-python-version=3.4 
--with-python-version=X.Y 
--with-python=/path/to/bin/python 
--with-python-root=/path/to 
./b2 -j4 address-model=64 --with-python stage 
builds python 3.4 lib (only) for 64 bit os, all binaries are in 
stage folder
… pick what to wrap 
Simple C API to wrap into Python 
int LZ4_compress(const char* source, 
char* dest, int sourceSize); 
int LZ4_decompress_safe ( 
const char* source, char* dest, 
int compressedSize, int maxDecompressedSize); 
basic API of lz4 compression library
Step #1: declare Python module 
#include <boost/python.hpp> 
#include <lz4.h> 
using namespace boost::python; 
BOOST_PYTHON_MODULE(lz4py) 
// make sure that your output binary will have same name 
// lz4py.so (not liblz4py.so ) or lz4py.dll 
{ 
// place for our wrappers 
}
basic wrappers... 
def("dump", // name of function on Python side 
LZ4_compress 
/*, return_value_policy<>() - optional */ ); 
def("load", LZ4_decompress_safe);
… but 
def() will wrap functions as they are … 
and call on Python side will not be so comfortable: 
lz4py.dump( 
input, # data to compress 
output, # ALLOCATED OUTPUT BUFFER (!?) 
size) # size of input data (!?) 
and function will return size of used bytes in output buffer 
it is too much C style - this is not Python...
Step #2: make it more Python 
add tiny wrapper in C++ code: 
const std::string compress(const std::string& d); 
const std::string decompress(const std::string& d); 
and wrap it for Python: 
def("dump", compress ); 
def("load", decompress); 
and … new trouble
… string and bytes 
In Python 3 all string are UNICODE: 
1. can’t return binary data as string - will fail 
a. could work for python 2 - but this is hidden 
problem in future 
2. need a way to return binary data 
a. convert output to bytes()
Step 4: type conversion 
Declare own type: 
class buffer { 
public: 
typedef boost::shared_ptr<char> data_ptr_t; 
public: 
buffer(data_ptr_t& data, int size): data_(data), size_(size){} 
int len() const { return size_; } 
char* const get_data() const { return data_.get(); } 
private: 
data_ptr_t data_; 
int size_; 
};
Converter to Python 
Converter interface declaration: 
template< typename T > 
struct type_into_python { 
static PyObject* convert( T const &); 
}; 
Converter implementation: 
template<> PyObject* type_into_python<buffer>::convert( 
buffer const& data){ 
return PyBytes_FromStringAndSize(data.get_data(), data.len()); 
}
Converter from Python: declaration 
template< typename T > 
struct type_from_python { 
type_from_python(){ 
converter::registry::push_back( convertible, 
construct, type_id<T>() ); 
} 
static void* convertible( PyObject* ); 
static void construct( 
PyObject*, 
converter::rvalue_from_python_stage1_data* ); 
};
Convert from Python: implement 
template<> void* type_from_python<buffer>::convertible( PyObject* obj){ 
return PyBytes_Check(obj) ? obj : nullptr; 
} 
template<> void type_from_python<buffer>::construct( PyObject* obj, 
converter::rvalue_from_python_stage1_data* data){ 
auto storage = reinterpret_cast< converter::rvalue_from_python_storage<buffer>* >( 
data )->storage.bytes; 
int size = PyBytes_Size(obj); 
buffer::data_ptr_t buffer_data = buffer::data_ptr_t(new char[size]); 
memcpy(buffer_data.get(), PyBytes_AsString(obj), size); 
new(storage) buffer(buffer_data, size); 
data->convertible = storage; 
}
New API 
New C++ functions: 
const buffer compress(buffer const& src); 
const buffer compress(std::string const& src); 
const buffer decompress(buffer const& src); 
Python exports: 
def("dump", static_cast<const buffer (*)(buffer const&)>( compress )); 
def("dump", static_cast<const buffer (*)(std::string const&)>( compress )); 
def("load", decompress);
Step #5: class 
Wrapp interface: 
class lz4_c { 
class bytes_ref{ 
PyObject* bytes_; 
public: 
int len() const { return 
PyBytes_Size(bytes_);} 
char const* data() const { return 
PyBytes_AsString(bytes_); } 
}; 
class buffer{ 
private: lz4_c& owner_; 
}; 
public: 
// initialize & use pool of preallocated blocks 
lz4_c(int block_max_size, int count); 
const buffer compress(bytes_ref const& src); 
const buffer compress(std::string const& src); 
const buffer decompress(bytes_ref const& 
src); 
void release(data_block_t&); 
};
Boost.Python class wrapper 
Declare Python class for lz4_c: 
class_<lz4_c>("lz4", 
init<int, int>( args("block_max_size", "count"))) 
//.def(init<int, int>( args("block_max_size", "count"))) 
● “lz4” - class name on Python side; 
● second argument - constructor, can be skipped if class have default one; 
● other constructors could be added using .def() like functions; 
● args - you can give names to your arguments and use named args in 
python;
Class methods 
extend our class by methods: 
.def("dump", static_cast<const lz4_c::buffer (lz4_c::*)( 
lz4_c::bytes_ref const&)>(&lz4_c::compress)) 
.def("dump", static_cast<const lz4_c::buffer (lz4_c::*)(std::string const&)>( 
&lz4_c::compress)) 
.def("load", &lz4_c::decompress) 
similar to regular functions.
Class properties 
can be exposed to python code: 
// read only 
.add_property("ratio", &lz4_c::ratio) 
// read / write 
.add_property("digit", make_getter(&lz4_c::digit), 
make_setter(&lz4_c::digit))
Exceptions 
class my_ex: public std::exception {}; 
... 
void translate_error( error const& my_ex); 
... 
//boost::python::register_exception_translator<T,F>(F) 
boost::python::register_exception_translator<my_ex>( 
translate_error)
And more 
STL type conversion: 
● std::map <-> dict(); 
● std::vector <-> list(), tuple() 
Define Python operators 
● __str__, __repr__, __ call__ 
● __add__, __lt__: 
o .def(self + self) 
o .def(self < self) 
Inheritance: 
● make available in Python 
● declare C++ relation 
Default args: 
● wrapper to allow default 
args: 
Python function pointers: 
● typedef boost::function<void 
(string s) > funcptr;
Return Value Policy 
● with_custodian_and_ward: Ties lifetimes of the arguments 
● with_custodian_and_ward_postcall: Ties lifetimes of the arguments and 
results 
● return_internal_reference: Ties lifetime of one argument to that of result 
● return_value_policy<T> with T one of: 
o reference_existing_object: naive (dangerous) approach 
o copy_const_reference: Boost.Python v1 approach 
o copy_non_const_reference: 
o manage_new_object: Adopt a pointer and hold the instance
Thank 
You ! 
Andriy.Ohorodnyk@globallogic.com

More Related Content

PDF
Boost.Python - domesticating the snake
PDF
Threads and Callbacks for Embedded Python
PDF
Cython - close to metal Python
PDF
Shared Memory Parallelism with Python by Dr.-Ing Mike Muller
PDF
Take advantage of C++ from Python
PDF
Introduction to Clime
PDF
Notes about moving from python to c++ py contw 2020
PDF
Про асинхронность / Максим Щепелин / Web Developer Wargaming
Boost.Python - domesticating the snake
Threads and Callbacks for Embedded Python
Cython - close to metal Python
Shared Memory Parallelism with Python by Dr.-Ing Mike Muller
Take advantage of C++ from Python
Introduction to Clime
Notes about moving from python to c++ py contw 2020
Про асинхронность / Максим Щепелин / Web Developer Wargaming

What's hot (20)

PDF
Python Developer Certification
PDF
Extending Python - EuroPython 2014
PDF
Brief Introduction to Cython
PDF
C++の話(本当にあった怖い話)
PDF
Introduction to cython: example of GCoptimization
PDF
RAII and ScopeGuard
PDF
Solid C++ by Example
PPTX
Mixing C++ & Python II: Pybind11
PDF
TDD in C - Recently Used List Kata
PDF
C++ How I learned to stop worrying and love metaprogramming
PDF
Reversing the dropbox client on windows
PDF
Easy native wrappers with SWIG
PDF
Tensor comprehensions
PDF
Python idiomatico
ODP
OpenGurukul : Language : C++ Programming
PPTX
C ISRO Debugging
PDF
Module Workshop NSC "Raspberry pi3 with Python" - Sanusi & Sasmitoh RR
PDF
Machine Learning on Code - SF meetup
PDF
Os Goodger
PDF
[GSoC 2017] gopy: Updating gopy to support Python3 and PyPy
Python Developer Certification
Extending Python - EuroPython 2014
Brief Introduction to Cython
C++の話(本当にあった怖い話)
Introduction to cython: example of GCoptimization
RAII and ScopeGuard
Solid C++ by Example
Mixing C++ & Python II: Pybind11
TDD in C - Recently Used List Kata
C++ How I learned to stop worrying and love metaprogramming
Reversing the dropbox client on windows
Easy native wrappers with SWIG
Tensor comprehensions
Python idiomatico
OpenGurukul : Language : C++ Programming
C ISRO Debugging
Module Workshop NSC "Raspberry pi3 with Python" - Sanusi & Sasmitoh RR
Machine Learning on Code - SF meetup
Os Goodger
[GSoC 2017] gopy: Updating gopy to support Python3 and PyPy
Ad

Viewers also liked (20)

PPS
Example Projectile Motion
PPTX
Boost.python
PPTX
Vasiliy Litvinov - Python Profiling
PDF
What’s eating python performance
PPTX
Denis Nagorny - Pumping Python Performance
PDF
The High Performance Python Landscape by Ian Ozsvald
PDF
Spark + Scikit Learn- Performance Tuning
PDF
Python profiling
PDF
Exploiting GPUs in Spark
PDF
Spark performance tuning - Maksud Ibrahimov
PDF
Interfacing C/C++ and Python with SWIG
PPTX
The Potential of GPU-driven High Performance Data Analytics in Spark
PDF
Python performance profiling
PPTX
GPU Support in Spark and GPU/CPU Mixed Resource Scheduling at Production Scale
PDF
Cornami Accelerates Performance on SPARK: Spark Summit East talk by Paul Master
PDF
How to Boost 100x Performance for Real World Application with Apache Spark-(G...
PDF
Making Sense of Spark Performance-(Kay Ousterhout, UC Berkeley)
PDF
GPU Support In Spark And GPU/CPU Mixed Resource Scheduling At Production Scale
PDF
Getting The Best Performance With PySpark
PDF
Boosting spark performance: An Overview of Techniques
Example Projectile Motion
Boost.python
Vasiliy Litvinov - Python Profiling
What’s eating python performance
Denis Nagorny - Pumping Python Performance
The High Performance Python Landscape by Ian Ozsvald
Spark + Scikit Learn- Performance Tuning
Python profiling
Exploiting GPUs in Spark
Spark performance tuning - Maksud Ibrahimov
Interfacing C/C++ and Python with SWIG
The Potential of GPU-driven High Performance Data Analytics in Spark
Python performance profiling
GPU Support in Spark and GPU/CPU Mixed Resource Scheduling at Production Scale
Cornami Accelerates Performance on SPARK: Spark Summit East talk by Paul Master
How to Boost 100x Performance for Real World Application with Apache Spark-(G...
Making Sense of Spark Performance-(Kay Ousterhout, UC Berkeley)
GPU Support In Spark And GPU/CPU Mixed Resource Scheduling At Production Scale
Getting The Best Performance With PySpark
Boosting spark performance: An Overview of Techniques
Ad

Similar to Boost.Python: C++ and Python Integration (20)

PDF
Start Wrap Episode 11: A New Rope
ODP
C Types - Extending Python
PPTX
Python with a SWIG of c++
PDF
PyCon2022 - Building Python Extensions
PDF
Pybind11 - SciPy 2021
PPTX
Kostiantyn Grygoriev "Wrapping C++ for Python"
PDF
Interfacing C++ with Python to boost your legacy apps with Python interfaces
PDF
Harmonic Stack for Speed
PDF
PyHEP 2018: Tools to bind to Python
PDF
OpenSAF Symposium_Python Bindings_9.21.11
PDF
Cluj.py Meetup: Extending Python in C
PPTX
Python Bindings Overview
PDF
Porting to Python 3
PDF
Plone ♥︎ Python 3
PDF
Porting to Python 3
PDF
Kyrylo Cherneha "C++ & Python Interaction in Automotive Industry"
PPT
Os Vanrossum
PDF
SciPy22 - Building binary extensions with pybind11, scikit build, and cibuild...
ODP
Programming Under Linux In Python
Start Wrap Episode 11: A New Rope
C Types - Extending Python
Python with a SWIG of c++
PyCon2022 - Building Python Extensions
Pybind11 - SciPy 2021
Kostiantyn Grygoriev "Wrapping C++ for Python"
Interfacing C++ with Python to boost your legacy apps with Python interfaces
Harmonic Stack for Speed
PyHEP 2018: Tools to bind to Python
OpenSAF Symposium_Python Bindings_9.21.11
Cluj.py Meetup: Extending Python in C
Python Bindings Overview
Porting to Python 3
Plone ♥︎ Python 3
Porting to Python 3
Kyrylo Cherneha "C++ & Python Interaction in Automotive Industry"
Os Vanrossum
SciPy22 - Building binary extensions with pybind11, scikit build, and cibuild...
Programming Under Linux In Python

More from GlobalLogic Ukraine (20)

PDF
GlobalLogic JavaScript Community Webinar #21 “Інтерв’ю без заспокійливих”
PPTX
Deadlocks in SQL - Turning Fear Into Understanding (by Sergii Stets)
PDF
GlobalLogic Java Community Webinar #18 “How to Improve Web Application Perfor...
PDF
GlobalLogic Embedded Community x ROS Ukraine Webinar "Surgical Robots"
PDF
GlobalLogic Java Community Webinar #17 “SpringJDBC vs JDBC. Is Spring a Hero?”
PDF
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
PPTX
Штучний інтелект як допомога в навчанні, а не замінник.pptx
PPTX
Задачі AI-розробника як застосовується штучний інтелект.pptx
PPTX
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
PDF
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
PDF
JavaScript Community Webinar #14 "Why Is Git Rebase?"
PDF
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
PPTX
Страх і сила помилок - IT Inside від GlobalLogic Education
PDF
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
PDF
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
PDF
“How to Secure Your Applications With a Keycloak?
PDF
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
PPTX
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
PDF
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
PDF
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"
GlobalLogic JavaScript Community Webinar #21 “Інтерв’ю без заспокійливих”
Deadlocks in SQL - Turning Fear Into Understanding (by Sergii Stets)
GlobalLogic Java Community Webinar #18 “How to Improve Web Application Perfor...
GlobalLogic Embedded Community x ROS Ukraine Webinar "Surgical Robots"
GlobalLogic Java Community Webinar #17 “SpringJDBC vs JDBC. Is Spring a Hero?”
GlobalLogic JavaScript Community Webinar #18 “Long Story Short: OSI Model”
Штучний інтелект як допомога в навчанні, а не замінник.pptx
Задачі AI-розробника як застосовується штучний інтелект.pptx
Що треба вивчати, щоб стати розробником штучного інтелекту та нейромереж.pptx
GlobalLogic Java Community Webinar #16 “Zaloni’s Architecture for Data-Driven...
JavaScript Community Webinar #14 "Why Is Git Rebase?"
GlobalLogic .NET Community Webinar #3 "Exploring Serverless with Azure Functi...
Страх і сила помилок - IT Inside від GlobalLogic Education
GlobalLogic .NET Webinar #2 “Azure RBAC and Managed Identity”
GlobalLogic QA Webinar “What does it take to become a Test Engineer”
“How to Secure Your Applications With a Keycloak?
GlobalLogic Machine Learning Webinar “Advanced Statistical Methods for Linear...
GlobalLogic Machine Learning Webinar “Statistical learning of linear regressi...
GlobalLogic C++ Webinar “The Minimum Knowledge to Become a C++ Developer”
Embedded Webinar #17 "Low-level Network Testing in Embedded Devices Development"

Boost.Python: C++ and Python Integration

  • 1. Boost.Python C++ & Python Integration
  • 2. Motivation Leveraging of strong sides in both languages: 1. C++: a. performance, b. effective resource management 2. Python: a. high coding performance, b. variety of available solutions c. easy to start
  • 3. Why Boost.Python? Python C-API: requires too much manual work SWIG (aka generators): usually requires manual adjusting - take time to understand “someones” code. Boost.Python (middleware lib): most flexible - expose what you need in the way you like.
  • 4. Getting Boost ready Getting Boost ready: get your copy of boost and build it: ./bootstrap.sh --prefix=../../ --with-python-version=3.4 --with-python-version=X.Y --with-python=/path/to/bin/python --with-python-root=/path/to ./b2 -j4 address-model=64 --with-python stage builds python 3.4 lib (only) for 64 bit os, all binaries are in stage folder
  • 5. … pick what to wrap Simple C API to wrap into Python int LZ4_compress(const char* source, char* dest, int sourceSize); int LZ4_decompress_safe ( const char* source, char* dest, int compressedSize, int maxDecompressedSize); basic API of lz4 compression library
  • 6. Step #1: declare Python module #include <boost/python.hpp> #include <lz4.h> using namespace boost::python; BOOST_PYTHON_MODULE(lz4py) // make sure that your output binary will have same name // lz4py.so (not liblz4py.so ) or lz4py.dll { // place for our wrappers }
  • 7. basic wrappers... def("dump", // name of function on Python side LZ4_compress /*, return_value_policy<>() - optional */ ); def("load", LZ4_decompress_safe);
  • 8. … but def() will wrap functions as they are … and call on Python side will not be so comfortable: lz4py.dump( input, # data to compress output, # ALLOCATED OUTPUT BUFFER (!?) size) # size of input data (!?) and function will return size of used bytes in output buffer it is too much C style - this is not Python...
  • 9. Step #2: make it more Python add tiny wrapper in C++ code: const std::string compress(const std::string& d); const std::string decompress(const std::string& d); and wrap it for Python: def("dump", compress ); def("load", decompress); and … new trouble
  • 10. … string and bytes In Python 3 all string are UNICODE: 1. can’t return binary data as string - will fail a. could work for python 2 - but this is hidden problem in future 2. need a way to return binary data a. convert output to bytes()
  • 11. Step 4: type conversion Declare own type: class buffer { public: typedef boost::shared_ptr<char> data_ptr_t; public: buffer(data_ptr_t& data, int size): data_(data), size_(size){} int len() const { return size_; } char* const get_data() const { return data_.get(); } private: data_ptr_t data_; int size_; };
  • 12. Converter to Python Converter interface declaration: template< typename T > struct type_into_python { static PyObject* convert( T const &); }; Converter implementation: template<> PyObject* type_into_python<buffer>::convert( buffer const& data){ return PyBytes_FromStringAndSize(data.get_data(), data.len()); }
  • 13. Converter from Python: declaration template< typename T > struct type_from_python { type_from_python(){ converter::registry::push_back( convertible, construct, type_id<T>() ); } static void* convertible( PyObject* ); static void construct( PyObject*, converter::rvalue_from_python_stage1_data* ); };
  • 14. Convert from Python: implement template<> void* type_from_python<buffer>::convertible( PyObject* obj){ return PyBytes_Check(obj) ? obj : nullptr; } template<> void type_from_python<buffer>::construct( PyObject* obj, converter::rvalue_from_python_stage1_data* data){ auto storage = reinterpret_cast< converter::rvalue_from_python_storage<buffer>* >( data )->storage.bytes; int size = PyBytes_Size(obj); buffer::data_ptr_t buffer_data = buffer::data_ptr_t(new char[size]); memcpy(buffer_data.get(), PyBytes_AsString(obj), size); new(storage) buffer(buffer_data, size); data->convertible = storage; }
  • 15. New API New C++ functions: const buffer compress(buffer const& src); const buffer compress(std::string const& src); const buffer decompress(buffer const& src); Python exports: def("dump", static_cast<const buffer (*)(buffer const&)>( compress )); def("dump", static_cast<const buffer (*)(std::string const&)>( compress )); def("load", decompress);
  • 16. Step #5: class Wrapp interface: class lz4_c { class bytes_ref{ PyObject* bytes_; public: int len() const { return PyBytes_Size(bytes_);} char const* data() const { return PyBytes_AsString(bytes_); } }; class buffer{ private: lz4_c& owner_; }; public: // initialize & use pool of preallocated blocks lz4_c(int block_max_size, int count); const buffer compress(bytes_ref const& src); const buffer compress(std::string const& src); const buffer decompress(bytes_ref const& src); void release(data_block_t&); };
  • 17. Boost.Python class wrapper Declare Python class for lz4_c: class_<lz4_c>("lz4", init<int, int>( args("block_max_size", "count"))) //.def(init<int, int>( args("block_max_size", "count"))) ● “lz4” - class name on Python side; ● second argument - constructor, can be skipped if class have default one; ● other constructors could be added using .def() like functions; ● args - you can give names to your arguments and use named args in python;
  • 18. Class methods extend our class by methods: .def("dump", static_cast<const lz4_c::buffer (lz4_c::*)( lz4_c::bytes_ref const&)>(&lz4_c::compress)) .def("dump", static_cast<const lz4_c::buffer (lz4_c::*)(std::string const&)>( &lz4_c::compress)) .def("load", &lz4_c::decompress) similar to regular functions.
  • 19. Class properties can be exposed to python code: // read only .add_property("ratio", &lz4_c::ratio) // read / write .add_property("digit", make_getter(&lz4_c::digit), make_setter(&lz4_c::digit))
  • 20. Exceptions class my_ex: public std::exception {}; ... void translate_error( error const& my_ex); ... //boost::python::register_exception_translator<T,F>(F) boost::python::register_exception_translator<my_ex>( translate_error)
  • 21. And more STL type conversion: ● std::map <-> dict(); ● std::vector <-> list(), tuple() Define Python operators ● __str__, __repr__, __ call__ ● __add__, __lt__: o .def(self + self) o .def(self < self) Inheritance: ● make available in Python ● declare C++ relation Default args: ● wrapper to allow default args: Python function pointers: ● typedef boost::function<void (string s) > funcptr;
  • 22. Return Value Policy ● with_custodian_and_ward: Ties lifetimes of the arguments ● with_custodian_and_ward_postcall: Ties lifetimes of the arguments and results ● return_internal_reference: Ties lifetime of one argument to that of result ● return_value_policy<T> with T one of: o reference_existing_object: naive (dangerous) approach o copy_const_reference: Boost.Python v1 approach o copy_non_const_reference: o manage_new_object: Adopt a pointer and hold the instance
  • 23. Thank You ! Andriy.Ohorodnyk@globallogic.com