[C++-sig] better way of returning python objects
Alexis H. Rivera-Rios
ahrivera at yahoo.com
Fri Jul 29 19:26:11 CEST 2005
Hi,
This is my situation. There is a C++ library called
gmtl that has been ported to python using Pyste and
Boost.Python.
In my code, I have a C++ class that looks like this
--- question #1 ---
class Entity
{
private:
gmtl::Point3d position;
gmtl::Vec3d velocity;
gmtl::Vec3d acceleration;
public:
void SetPosition(const gmtl::Point3d& pos) ...
gmtl::Point3d GetPosition() const ...
void SetVelocity(const gmtl::Vec3d& vel) ...
gmtl::Vec3d GetVelocity() const ...
void SetAcceleration(const gmtl::Vec3d& acc) ...
gmtl::Vec3d GetAcceleration() const ...
};
I want to be able to do this in python
import gmtl; <-- this I can do already because the
library has python bindings
from MyModule import *
t = Entity
t.SetPosition(gmtl.Point3d(1,2,3))
y = t.GetPosition()
The only way I've figure to do this is the following:
(this is an excerpt of what pyste generated, I changed
the Get/Set methods to this)
scope* StatATA_Entity_scope = new scope(
class_< StatATA::Entity, boost::noncopyable,
StatATA_Entity_Wrapper >("Entity", init< >())
.def("SetPosition", &SetPosition)
.def("GetPosition", &GetPosition)
);
Where,
void SetPosition( StatATA::Entity &e, const object
&pos )
{
gmtl::Point3d
p(extract<double>(pos.attr("__getitem__")(0)),
extract<double>(pos.attr("__getitem__")(1)),
extract<double>(pos.attr("__getitem__")(2)));
e.SetPosition(p);
}
object GetPosition( StatATA::Entity &e )
{
object main_module((
handle<>(borrowed(PyImport_AddModule("__main__")))));
object main_namespace = main_module.attr("__dict__");
object result((handle<>(
PyRun_String("gmtl.Point3d()"
, Py_eval_input
, main_namespace.ptr()
, main_namespace.ptr()))
));
gmtl::Point3d t (e.GetPosition());
result[0] = t[0];
result[1] = t[1];
result[2] = t[2];
return result;
}
This works. But, is there a better way?
---- question #2 ---
Now, my entity has additional member variables with
other gmtl types.
It seems that I have to repeat the same process with
each type.
I want to generalize that function so I can specify
the object function to call and the destination type:
class_< StatATA::Entity, boost::noncopyable,
StatATA_Entity_Wrapper >("Entity", init< >())
.def("SetPosition",
&GenericSet<Entity::SetPosition,gmtl::Point3d>)
.def("SetVelocity",
&GenericSet<Entity::SetVelocity,gmtl::Vec3d>)
);
The closest I've got to do that is this class:
template <class Object>
struct GenSet
{
typedef void (Object::*MemberFunc) (const
gmtl::Point3d&) ;
MemberFunc f;
GenSet(MemberFunc x)
{
f = x;
};
void operator()(Object &obj, const object &pos)
{
gmtl::Point3d
p(extract<double>(pos.attr("__getitem__")(0)),
extract<double>(pos.attr("__getitem__")(1)),
extract<double>(pos.attr("__getitem__")(2)));
(obj.*f)(p);
}
};
So in theory I can do the following:
GenSet<Entity> xxx(&Entity::SetPosition)
xxx(myobject, bla)
But I run into the following problems when I try to
use this in the code:
1) declaring an object without the variable name gives
a syntax error:
GenSet<Entity> (&Entity::SetPosition)
c:\Development\PyStatATA\pystatata.cpp(119):
error C2761: 'void StatATA::Entity::SetPosition(const
gmtl::Point3d &)' : member function redeclaration not
allowed
Why does that mean?
2) Passing the class to the .def function doesn't
compile either:
GenSet<Entity> xxx(&Entity::SetPosition)
class_< StatATA::Entity, boost::noncopyable,
StatATA_Entity_Wrapper >("Entity", init< >())
.def("SetPosition", &xxx)
c:\Boost\include\boost-1_32\boost\python\class.hpp(500)
: error C2784:
'boost::mpl::vector17<RT,most_derived<Target,ClassT>::type&,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>
boost::python::detail::get_signature(RT (__thiscall
ClassT::*
)(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14)
volatile const,Target *)' : could not deduce template
argument for 'T2 (__thiscall T3::*
)(T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18)
volatile const' from
'`anonymous-namespace'::GenSet<Object> with
[Object=StatATA::Entity]';
c:\Boost\include\boost-1_32\boost\python\signature.hpp(164)
: see declaration of
'boost::python::detail::get_signature';
c:\Boost\include\boost-1_32\boost\python\class.hpp(237)
: see reference to function template instantiation
'void
boost::python::class_<W,X1,X2>::def_impl<W,F,boost::python::detail::def_helper<T1>>(T
*,const char *,Fn,const Helper &,...) with
[W=StatATA::Entity,X1=boost::noncopyable,X2=`anonymous-namespace'::StatATA_Entity_Wrapper,F=`anonymous-namespace'::GenSet<StatATA::Entity>
*__w64 ,T1=const char
*,T=StatATA::Entity,Fn=`anonymous-namespace'::GenSet<StatATA::Entity>
*__w64 ,Helper=boost::python::detail::def_helper<const
char *>]' being compiled;
c:\Development\PyStatATA\pystatata.cpp(140) : see
reference to function template instantiation
'boost::python::class_<W,X1,X2>::self
&boost::python::class_<W,X1,X2>::def<`anonymous-namespace'::GenSet<Object>*__w64
>(const char *,F) with
[W=StatATA::Entity,X1=boost::noncopyable,X2=`anonymous-namespace'::StatATA_Entity_Wrapper,Object=StatATA::Entity,F=`anonymous-namespace'::GenSet<StatATA::Entity>
*__w64 ]' being compiled
c:\Boost\include\boost-1_32\boost\python\class.hpp(500)
: error C2780:
'boost::mpl::vector17<RT,ClassT&,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>
boost::python::detail::get_signature(RT (__thiscall
ClassT::*
)(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14)
volatile const)' : expects 1 arguments - 2 provided;
c:\Boost\include\boost-1_32\boost\python\signature.hpp(146)
: see declaration of
'boost::python::detail::get_signature'
c:\Boost\include\boost-1_32\boost\python\class.hpp(500)
: error C2784:
'boost::mpl::vector17<RT,most_derived<Target,ClassT>::type&,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>
boost::python::detail::get_signature(RT (__thiscall
ClassT::*
)(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14)
volatile,Target *)' : could not deduce template
argument for 'T2 (__thiscall T3::*
)(T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18)
volatile' from '`anonymous-namespace'::GenSet<Object>
with [Object=StatATA::Entity]';
c:\Boost\include\boost-1_32\boost\python\signature.hpp(164)
: see declaration of
'boost::python::detail::get_signature'
c:\Boost\include\boost-1_32\boost\python\class.hpp(500)
: error C2780:
'boost::mpl::vector17<RT,ClassT&,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>
boost::python::detail::get_signature(RT (__thiscall
ClassT::*
)(T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14)
volatile)' : expects 1 arguments - 2 provided;
c:\Boost\include\boost-1_32\boost\python\signature.hpp(146)
: see declaration of
'boost::python::detail::get_signature'
...
So I guess it means we can't pass functors to the .def
functions?
In summary,
- Is there a better way to convert a c++ object to its
respective python object without me having to
expose the type since that has been done for me?
- Assuming that my solution for the previous question
is acceptable,
how can I generatize my setposition function so its
parameterized on the gmtl type, and object function in
a way that works
with the .def function?
Any comments or feedback will be greatly appreciated,
Alexis
Programming Tutorial:
In Python: To do this, do this
In Perl: To do this, do this or this or this or this...
In C: To do this, do this, but be careful
In C++: To do this, do this, but don't do this, be careful of this, watch out for this, and whatever you do, don't do this
____________________________________________________
Start your day with Yahoo! - make it your home page
http://www.yahoo.com/r/hs
More information about the Cplusplus-sig
mailing list