c++ - Python C API - How to construct object from PyObject -


i'm looking find out if there's nice, "native" way construct object given pyobject* known type.

here code stands:

c++

void add_component(boost::python::object& type) {     auto constructed_type = type(); // doesn't construct anything! } 

python

o = gameobject() o.add_component(cameracomponent) 

my code executing entire function fine, constructor never triggered cameracomponent.

so question is, how i, given pyobject* known a type, construct instance of type?

many in advance.

if boost::python::object references type, invoking construct object referenced type:

boost::python::object type = /* py_type */; boost::python::object object = type(); // isinstance(object, type) == true 

as in python object, accepting arguments python boost::python::object allow type of object, not type. long object callable (__call___), code succeed.


on other hand, if want guarantee type provided, 1 solution create c++ type represents python type, accept argument, , use custom converter construct c++ type if python type provided.

the following type_object c++ type represents python object py_type.

/// @brief boost::python::object refers type. struct type_object:    public boost::python::object {   /// @brief if object type, refer it.  otherwise,   ///        refer instance's type.   explicit   type_object(boost::python::object object):     boost::python::object(object)   {     if (!pytype_check(object.ptr()))     {       throw std::invalid_argument("type_object requires python type");     }   } };  ...  // accepts python type. void add_component(type_object type) { ... } 

the following custom converter construct type_object instance if provided pyobject* py_type:

/// @brief enable automatic conversions type_object. struct enable_type_object {   enable_type_object()   {     boost::python::converter::registry::push_back(       &convertible,       &construct,       boost::python::type_id<type_object>());   }    static void* convertible(pyobject* object)   {     return pytype_check(object) ? object : null;   }    static void construct(     pyobject* object,     boost::python::converter::rvalue_from_python_stage1_data* data)   {     // obtain handle memory block converter has allocated     // c++ type.     namespace python = boost::python;     typedef python::converter::rvalue_from_python_storage<type_object>                                                                  storage_type;     void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;      // construct type object within storage.  object borrowed      // reference, create handle indicting borrowed proper     // reference counting.     python::handle<> handle(python::borrowed(object));     new (storage) type_object(python::object(handle));      // set convertible indicate success.      data->convertible = storage;   } };  ...  boost_python_module(...) {   enable_type_object(); // register type_object converter. } 

here complete example demonstrating exposing function requires python type, constructs instance of type:

#include <iostream> #include <stdexcept> // std::invalid_argument #include <boost/python.hpp>  /// @brief boost::python::object refers type. struct type_object:    public boost::python::object {   /// @brief if object type, refer it.  otherwise,   ///        refer instance's type.   explicit   type_object(boost::python::object object):     boost::python::object(object)   {     if (!pytype_check(object.ptr()))     {       throw std::invalid_argument("type_object requires python type");     }   } };  /// @brief enable automatic conversions type_object. struct enable_type_object {   enable_type_object()   {     boost::python::converter::registry::push_back(       &convertible,       &construct,       boost::python::type_id<type_object>());   }    static void* convertible(pyobject* object)   {     return pytype_check(object) ? object : null;   }    static void construct(     pyobject* object,     boost::python::converter::rvalue_from_python_stage1_data* data)   {     // obtain handle memory block converter has allocated     // c++ type.     namespace python = boost::python;     typedef python::converter::rvalue_from_python_storage<type_object>                                                                  storage_type;     void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;      // construct type object within storage.  object borrowed      // reference, create handle indicting borrowed proper     // reference counting.     python::handle<> handle(python::borrowed(object));     new (storage) type_object(python::object(handle));      // set convertible indicate success.      data->convertible = storage;   } };  // mock api. struct gameobject {}; struct cameracomponent {   cameracomponent()   {     std::cout << "cameracomponent()" << std::endl;   } };  boost::python::object add_component(gameobject& /* self */, type_object type) {   auto constructed_type = type();   return constructed_type; }  boost_python_module(example) {   namespace python = boost::python;    // enable receiving type_object arguments.   enable_type_object();    python::class_<gameobject>("gameobject")     .def("add_component", &add_component);    python::class_<cameracomponent>("cameracomponent"); } 

interactive usage:

>>> import example >>> game = example.gameobject() >>> component = game.add_component(example.cameracomponent) cameracomponent() >>> assert(isinstance(component, example.cameracomponent)) >>> try: ...     game.add_component(component) # throws boost.python.argumenterror ...     assert(false) ... except typeerror: ...     assert(true) ... 

Comments

Popular posts from this blog

sql - VB.NET Operand type clash: date is incompatible with int error -

SVG stroke-linecap doesn't work for circles in Firefox? -

python - TypeError: Scalar value for argument 'color' is not numeric in openCV -