Proceedings of the 8th Annual Python in Science Conference
Proceedings of the 8th Annual Python in Science Conference
Proceedings of the 8th Annual Python in Science Conference
- No tags were found...
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Convert-XY: type-safe <strong>in</strong>terchange <strong>of</strong> C++ and <strong>Python</strong> conta<strong>in</strong>ers for NumPy extensionsCopyThis compound type specifies that <strong>the</strong> str<strong>in</strong>g keys andvector elements be copied but <strong>the</strong> buffer po<strong>in</strong>ter to <strong>the</strong>arrays should be reused. Figure 5 illustrates how thisrecursive <strong>in</strong>stantiation works.DefaultToCPPAction::ActionCopyKeyActionDefaultToCPPAction::ActionActionCopyValueActionDefaultToCPPAction::ActionActionCopyElementActionDefaultToCPPAction Action::ActionActionAllocateCopyCopyFigure 5 The process <strong>of</strong> conversion is deducedat compile time via recursive <strong>in</strong>stantiation <strong>of</strong>DefaultToCPPAction.The process <strong>of</strong> conversion can be overridden by pass<strong>in</strong>gas a template argument a different Action type. Forexample, suppose <strong>the</strong> target BasicImage was allocatedfrom elsewhere (e.g. a special malloc function thatproperly aligns buffers), we can override <strong>the</strong> defaultconversion action (Reuse) so Copy is used as <strong>the</strong>Action <strong>in</strong>stead. The ConvertXY::convert_overridefunction can be used for this purpose:void example(PyObject *x, BasicImage &y) {convert_override(x, y);}Suppose a C++ object y <strong>of</strong> a compound conta<strong>in</strong>er typealready exists, e.g. an object <strong>of</strong> type map. In this case, <strong>the</strong> keys shouldnot be copied but we must ensure that <strong>the</strong> C++ mapconta<strong>in</strong>s exactly <strong>the</strong> same set <strong>of</strong> keys as <strong>the</strong> <strong>Python</strong>dictionary. This is done by first check<strong>in</strong>g that <strong>the</strong> size<strong>of</strong> <strong>the</strong> dictionary is <strong>the</strong> same as <strong>the</strong> std::map and <strong>the</strong>nmak<strong>in</strong>g sure each unique key <strong>in</strong> <strong>the</strong> dictionary is equivalentto some unique key <strong>in</strong> <strong>the</strong> map.The contents <strong>of</strong> a dictionary <strong>of</strong> arrays can be copied<strong>in</strong>to a std::map <strong>of</strong> exist<strong>in</strong>g BasicImage buffers as follows:void example(PyObject *x,map &y) {convert_override(x, y);}The CheckSize simple checks that <strong>the</strong> size <strong>of</strong><strong>the</strong> std::map and <strong>Python</strong> map are equivalent.CheckExists ensures each key <strong>in</strong> <strong>the</strong> <strong>Python</strong> map isalso <strong>in</strong> <strong>the</strong> STL map.Reference count<strong>in</strong>g is automatically handled dur<strong>in</strong>gconversion with PyCXX. In cases where <strong>the</strong> flow <strong>of</strong>execution may return to <strong>Python</strong> after conversion, Py-CXX can be used to ensure objects that are <strong>in</strong> use byC++ rout<strong>in</strong>es don’t get prematurely destroyed.:void example(PyObject *x,BasicImage &y) {// The l<strong>in</strong>e below is safe.convert(x,y);// However, if it can’t be guaranteed that program// control flow will never return to <strong>Python</strong>// for <strong>the</strong> rest <strong>of</strong> this function, use PyCXX’s// Py::Object to <strong>in</strong>crement <strong>the</strong> reference count.Py::Object obj(x);// If <strong>the</strong> flow <strong>of</strong> execution returns to <strong>Python</strong> while// execut<strong>in</strong>g <strong>the</strong> function below, y will always po<strong>in</strong>t// to a valid buffer.compute(y);}The O<strong>the</strong>r Way Around: from C++ to <strong>Python</strong>When convert<strong>in</strong>g from C++ to <strong>Python</strong>, <strong>the</strong> typestructure <strong>of</strong> <strong>the</strong> target <strong>Python</strong> object must beprespecified at compile time (e.g. <strong>the</strong> type <strong>of</strong> <strong>the</strong><strong>Python</strong> object to be created is static). This is notstraightforward s<strong>in</strong>ce <strong>the</strong>re is sometimes more thanone compatible <strong>Python</strong> type for a C++ type. Forexample, an STL vector can be converted to a <strong>Python</strong>list, tuple, or NumPy object array. In Convert-XYthis is deduced with a compile-time-only Structuremetatype deduced by recursive <strong>in</strong>stantiation <strong>of</strong>DefaultTo<strong>Python</strong>Structure::Structure.Figure 6illustrates how DefaultTo<strong>Python</strong>Structureis recursively <strong>in</strong>stantiated to yield a default <strong>Python</strong>target type.To<strong>Python</strong>DefaultStructure::StructureStructurePyDictKeyStructureTo<strong>Python</strong>DefaultStructure::StructureStructurePyStr<strong>in</strong>gNon-term<strong>in</strong>al Structure TypeTerm<strong>in</strong>al Structure TypeExpanded typedefValueStructureTo<strong>Python</strong>DefaultStructure::StructureElementStructurePyListElementStructureDefault::StructureStructurePyArrayPyDictFigure 6 The default <strong>Python</strong> type when convert<strong>in</strong>gfrom C++ to <strong>Python</strong> is deduced by recursive <strong>in</strong>stantiation<strong>of</strong> To<strong>Python</strong>DefaultStructure.As <strong>the</strong> figure illustrates, <strong>the</strong> default type for a <strong>Python</strong>target given a source object that’s an STL map mapp<strong>in</strong>gstr<strong>in</strong>g to vectors <strong>of</strong> images is PyDict. If a tuple is preferredover a list, <strong>the</strong> default structure can be overridenas follows:c○2009, D. Eads, E. Rosten 32