On 04/18/2013 11:44 AM, Alex Leach wrote:
Thank you for the quick response!
On Thu, 18 Apr 2013 15:24:09 +0100, Jim Bosch <tallji...@gmail.com> wrote:
If you go with writing your own PyTypeObject, you will indeed have a lot
more control, but it will greatly limit how much Boost.Python you can use (no
class_, for instance, at least), and you'll need to dive deep into the
Boost.Python implementation to learn how and when you can use it. I'd only
consider recommending this approach if you wanted to wrap one or two simple
classes this way and then use regular Boost.Python for everything else.
No class_<..> type would be a problem, as I've already exposed a lot of its
derived classes this way.. There's got to be about 100 in total. :-\
I think the best solution would probably be to use shared_ptr with a custom
deleter, as that gives you control over how your objects are allocated while
giving Boost.Python an object it knows how to handle extremely well. One key
ingredient of this is that instead of wrapping C++ constructors, you'll want to
wrap factory functions that return shared_ptrs. You can even wrap such
functions as Python constructors using make_constructor.
I've already had to do this once, so I've got some experience with the
technique, although can't remember exactly why it was needed. Thank you for a
viable option, though!
All that said, my first recommendation would be to try to wrap it (or at
least a subset of it) without trying to get the optimal memory performance
first, and only fix it if it actually is a performance problem. You might be
surprised at where the time ends up going.
:) Lol, yes, I can see how attempting to define a new PyTypeObject could become
very time-consuming!
If I were to go this route though (I probably will), is there a Boost Python
registry or something where I can register these new types? I just thought to
look into list.hpp, as I figure the boost::python::list would probably make use
of the PyListType, which could be thought of as a similar PyTypeObject
specialisation to one I might like to create.
You can't really register the types themselves. All you can do is register custom
converters for them, i.e. You'll need to read the code and comments in the
"converter" subdirectories of the Boost.Python source to really learn how to do
that, though I think there are some how-tos scattered about the web.
That would be enough to allow you to wrap functions and member functions that
take these objects using boost::python::make_function and the like, and you
could then add those to your type object using C API calls (PyObject_SetAttr)
or their Boost.Python equivalents. Even so, you're starting down what seems
like a really painful road.
......
Now I've done a little more digging, I think I have an idea of how to do it,
which I'll detail now.. Any tips, pointers or advice in Boost::Python'ising it
would be appreciated, as I have next to no experience with the Python-C API
beyond Boost.
Resources
---------
Worth mentioning that the best (simplest) resources I've found to go by, are:
[1] - For the C-Python side:
http://docs.python.org/2/extending/newtypes.html
[2] - For Boost-Python side:
http://www.boost.org/doc/libs/1_53_0/boost/python/list.hpp
Steps to expose:-
-----------------
a. - Create mytypeobject.h, a raw C-Python extension type, as explained in [1].
a.i. - Create unit-test, by deriving such a type in Python, making a
few instances, deleting some and leaving others to the garbage
collector.
b. Create mytypeobject.hpp, where a type similar to boost::python::list is
declared. Register it, with for example:-
// From list.hpp:-
//
namespace converter
{
template <>
struct object_manager_traits<list>
: pytype_object_manager_traits<&PyList_Type,list>
{
};
}
Doing this sort of thing will allow you to get a Python object that's an
instance of your PyTypeObject. It might be a useful bit of utility code, but
it's really not directly what you want, I think, which is to be able to convert
between Python instances of your class and C++ instances.
What else?
----------
I very much doubt it will be this simple, as any exposed class_<> would
probably still attach a typical PyObject, thereby using PyTypeObject's memory
management functions, rather than that of any type object specialisation.
Example
-------
For example, let's suppose PyListObject has some functionality I need in an
exposed class, and I need the garbage collector to use PyListType instead of
PyTypeObject, when managing its memory.
Is there a way to attach a PyListObject to a class_<> instance, instead of a
PyObject? Perhaps an alternative to the class_<> template could be designed to use
any arbitrary type, instead of the default PyTypeObject. Something which could be used like
this would be cool:-
boost::python::type_object_<PyListType, PyList, [boost::noncopyable]>
("alt_list", "PyListObject wrapped in Boost.",
init<>())
.def("append", PyList_Append)
/// ...
;
How much farther do you think I would need to dig into Boost internals to
implement such functionality? Worth it?
It's pretty much definitely not worth it, IMO; you'd have to essentially duplicate and
rewrite major parts of Boost.Python to support putting a custom PyTypeObject in a class_.
The class_ infrastructure relies very heavily not just on its own PyTypeObject hiearchy,
but also on a custom metaclass. In fact, now that I think about it, you'll probably need
to do some of that even if you don't try to use class_ or something like it. I was
originally thinking that maybe you could get away with essentially wrapping your own
classes just using the Python C API directly (i.e. following the approach in the
"extending and embedding" tutorial in the official Python docs), but then use
Boost.Python to wrap all of your functions and handle type conversion. But even that
seems like it's pretty difficult.
So I guess the summary is that I think you may be making a mistake by taking
this approach, but I'm sure you'll learn something either way. You've been
warned ;-)
Jim
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig