That'll work in the simplified example I had. But it's going to be a huge pain for many of my actual classes. I guess I'll have to do it like this if there's no other options? Though at that point I might need to limit how much functionality I'm exporting out to python. > Date: Fri, 8 Jun 2012 21:22:47 -0400 > From: tallji...@gmail.com > To: super24bitso...@hotmail.com > CC: cplusplus-sig@python.org > Subject: Re: [C++-sig] Properly copying wrapped classes > > It looks like the only way to get a wrapper object is by actually > invoking the Python constructor. That's not what I expected, but it's > reasonable and not completely unexpected. And it avoids problems that > might arise if you had any Python-only attributes attached to the > wrapper object. > > So I think you'll need to try a new approach, one that involves calling > a wrapped copy constructor. > > Would it meet your needs to just remove the __copy__ and __deepcopy__ > implementations, and change the Python derived class to something like > what's below? > > class Der(BaseClass): > def Test(self): > print "Python Side Test. ID: " + str(self.GetID()) > > def Clone(self): > print "Python Clone" > result = Der(...) # whatever constructor args you need in Python > BaseClass.__init__(result, self) > return result > > > (btw, apologies to the rest of the list - I accidentally replied without > including the list a few emails back, but all you've missed are a number > of ideas that don't work) > > > Jim > > > > > > On 06/08/2012 08:40 PM, Jay Riley wrote: > > I replaced my template copy with > > > > object bc_copy(object copyable, dict memo) > > { > > object copyMod = import("copy"); > > object deepcopy = copyMod.attr("deepcopy"); > > > > BaseClassWrap *newCopyable(new BaseClassWrap(extract<const BaseClassWrap > > &>(copyable))); > > > > BaseClass tmp = boost::python::extract<BaseClass const &>(copyable); > > object result(tmp); > > > > int copyableId = (int)(copyable.ptr()); > > memo[copyableId] = result; > > > > extract<dict>(result.attr("__dict__"))().update( > > deepcopy(extract<dict>(copyable.attr("__dict__"))(), > > memo)); > > > > return result; > > } > > > > and wrapped > > > > class_<BaseClass, boost::shared_ptr<BaseClassWrap> >("BaseClass", init<>()) > > .def(init<const BaseClass&>()) > > .def(init<const BaseClassWrap&>()) > > .def("GetID", &BaseClassWrap::GetIDDefault) > > .def("Clone", &BaseClassWrap::CloneDefault) > > .def("Test", &BaseClassWrap::TestDefault) > > .def("__copy__", &generic__copy__< BaseClass >) > > .def("__deepcopy__", &bc_copy) > > ; > > > > But I'm still getting the non overriden behaviour. Calling Test on the > > clone prints out the C++ side code, while the non clone prints out the > > python side code. > > > > > > > > > > > > > Date: Thu, 7 Jun 2012 17:13:55 -0400 > > > From: jbo...@astro.princeton.edu > > > To: super24bitso...@hotmail.com > > > Subject: Re: [C++-sig] Properly copying wrapped classes > > > > > > On 06/05/2012 12:41 AM, Jay Riley wrote: > > > > That got rid of the compile time errors. However, On the python side I > > > > get the following error when I try to clone: > > > > > > > > > > > > File ... line 9 in Clone > > > > return copy.deepcopy(self) > > > > File C:\Python27\Lib\copy.py" line 174 in deepcopy > > > > y = copier(memo) > > > > TypeError: No to_python (by-value) converter for C++ type: class > > > > BaseClassWrap > > > > > > > > > > Hmm. I would have expected that to work. As long as BaseClass can be > > > instantiated itself (i.e. it isn't pure abstract), you could try this in > > > the copy/deepcopy implementation: > > > > > > BaseClass tmp = boost::python::extract<BaseClass const &>(copyable); > > > object result(tmp); > > > > > > (I don't remember which of these types your Copyable template parameter > > > was, but I'd recommend just trying to write this in a non-template > > > function until you get it working). > > > > > > That will involve one extra copy, but it should invoke the BaseClass > > > by-value converter instead of the BaseClassWrap by-value converter, and > > > I *think* that should do the right thing. > > > > > > > > > Jim > > > > > > > > > > > > > > > > In the interest of trying it out, I added the BaseClassWrap to the > > > > python module > > > > > > > > class_<BaseClassWrap, bases<BaseClass> >("BaseClassWrap", > > init<PyObject*>()) > > > > .def(init<PyObject*, const BaseClass&>()) > > > > .def(init<PyObject*, const BaseClassWrap&>()) > > > > .def("__copy__", &generic__copy__< BaseClassWrap >) > > > > .def("__deepcopy__", &generic__deepcopy__< BaseClassWrap >) > > > > ; > > > > > > > > But this put me back at square one, where self isn't indicative of the > > > > cloned instance. > > > > > > > > Just in the interest of seeing the effect, I changed my python > > exposing to: > > > > > > > > class_<BaseClass, boost::shared_ptr<BaseClassWrap> >("BaseClass", > > init<>()) > > > > .def(init<const BaseClass&>()) > > > > .def(init<const BaseClassWrap&>()) > > > > .def("GetID", &BaseClassWrap::GetIDDefault) > > > > .def("Clone", &BaseClassWrap::CloneDefault) > > > > .def("Test", &BaseClassWrap::TestDefault) > > > > .def("__copy__", &generic__copy__< BaseClass >) > > > > .def("__deepcopy__", &generic__deepcopy__< BaseClass >) > > > > ; > > > > > > > > But as expected, the overloading doesn't work on clones made with this > > > > exposing. Anything else I should try? > > > > > > > > Again, thanks for the help so far, appreciate it. > > > > > > > > > > > > > > > > > > > > > Date: Mon, 4 Jun 2012 11:52:42 -0400 > > > > > From: jbo...@astro.princeton.edu > > > > > To: super24bitso...@hotmail.com > > > > > Subject: Re: [C++-sig] Properly copying wrapped classes > > > > > > > > > > On 06/04/2012 12:58 AM, Jay Riley wrote: > > > > > > > > > > > > Hi Jim, > > > > > > Thanks for the help so far. From what you said, I should be able to > > > > change my deepcopy to this correct? > > > > > > > > > > > > template<class Copyable> object generic__deepcopy__(object > > > > copyable, dict memo) { object copyMod = import("copy"); object deepcopy > > > > = copyMod.attr("deepcopy"); > > > > > > Copyable *newCopyable(new Copyable(extract<const Copyable > > > > &>(copyable))); //object > > > > > > result(boost::python::detail::new_reference(managingPyObject(newCopyable))); > > > > > > object result(extract<const Copyable&>(copyable)()); > > > > > > // HACK: copyableId shall be the same as the result of id(copyable) > > > > //in Python - // please tell me that there is a better way! (and which > > > > ;-p) int copyableId = (int)(copyable.ptr()); memo[copyableId] = result; > > > > > > extract<dict>(result.attr("__dict__"))().update( > > > > deepcopy(extract<dict>(copyable.attr("__dict__"))(), memo)); > > > > > > return result; } > > > > > > When I attempt to compile it gives me the following error: > > > > > > Error 48 error C2664: 'boost::python::api::object::object(const > > > > boost::python::api::object&)' : cannot convert parameter 1 from > > > > 'boost::python::api::object (__cdecl *)(boost::python::extract<T> > > > > (__cdecl *)(void))' to 'const boost::python::api::object&' > > > > c:\khmp\src\engine\scripting\python\scripthelpers.h 67 > > > > > > Did you mean something else? This level of boost python is above my > > > > head, so I'm a bit lost > > > > > > > > > > > > > > > > It looks like the version I gave you is a bad corner case where the > > > > > compiler is incapable of parsing a constructor properly when > > templates > > > > > and overloaded function-call operators are involved; I always forget > > > > > exactly when that comes into play (not a compiler bug, just a > > weird part > > > > > of the standard, I think). In any case, I think separating it > > into two > > > > > lines should fix the problem: > > > > > > > > > > const Copyable & tmp = extract<const Copyable &>(copyable); > > > > > object result(tmp); > > > > > > > > > > Let me know if that doesn't work either; at that point I should > > try to > > > > > compile it myself and see what's going on. > > > > > > > > > > Jim > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >> Date: Sun, 3 Jun 2012 11:25:38 -0400 > > > > > >> From: jbo...@astro.princeton.edu > > > > > >> To: cplusplus-sig@python.org > > > > > >> CC: super24bitso...@hotmail.com > > > > > >> Subject: Re: [C++-sig] Properly copying wrapped classes > > > > > >> > > > > > >> On 05/31/2012 08:49 PM, Jay Riley wrote: > > > > > >>> I'm having a problem with some python objects derived in python. > > > > I have > > > > > >>> a Clone method that's supposed to make a full copy of these > > python > > > > > >>> inherited objects, but it isn't working. The problem is my > > wrapper > > > > > >>> class' PyObject* self isn't getting copied, so when I use > > > > > >>> call_method<>(self, "method name"), self will never point to the > > > > copied > > > > > >>> instance. Here's a brief example showing the issue > > > > > >>> > > > > > >> > > > > > >> <snip> > > > > > >> > > > > > >>> > > > > > >>> Sorry about the length, just want to make sure I got everything > > > > relevant > > > > > >>> in. When I run this code, it prints: > > > > > >>> > > > > > >>> Python Clone > > > > > >>> Python Side Test. ID: 1 > > > > > >>> Python Side Test. ID: 1 > > > > > >>> Original ID 1 > > > > > >>> Clone ID 1 > > > > > >>> > > > > > >>> this is wrong because Clone ID should be 2 (inspecting the object > > > > > >>> confirms it is 2). Like I said I'm pretty sure the problem is > > > > that the > > > > > >>> wrapper class' copy constructor only makes a copy of the > > > > PyObject* self, > > > > > >>> not a full copy. This is how every reference doc I saw was doing > > > > class > > > > > >>> wrapping, but isn't this wrong? Should we be making a full copy > > > > of the > > > > > >>> PyObject*? How would I go about doing that, or otherwise > > modifying my > > > > > >>> classes to get the behaviour I expect. > > > > > >>> > > > > > >> > > > > > >> There are a couple of things here that probably need to be > > addressed: > > > > > >> > > > > > >> - Be wary of relying on copy-constructor side effects to > > demonstrate > > > > > >> whether something is working; the compiler is allowed to elide > > copy > > > > > >> constructors under many conditions, which might result in > > misleading > > > > > >> results. That said, I don't think that's what's causing your > > problem > > > > > >> here (or at least not all of it). > > > > > >> > > > > > >> - Your implementations of __copy__ and __deepcopy__ won't work > > with > > > > > >> polymorphic wrapper classes, because they construct a BaseClass > > > > instance > > > > > >> and tell Boost.Python to wrap it by managing the new > > reference. That > > > > > >> necessarily makes a Python object that holds a BaseClass object, > > > > not one > > > > > >> that holds a BaseClassWrap object. If you want to get a > > BaseClassWrap > > > > > >> Python object, you want to pass it by value to Boost.Python; that > > > > should > > > > > >> invoke the BaseClassWrap copy constructor and pass it a new > > > > PyObject* to > > > > > >> manage (so it doesn't have to copy the PyObject* itself). > > > > > >> > > > > > >> I think that just means you can remove the "managingPyObject" > > > > function, > > > > > >> and instead use: > > > > > >> > > > > > >> object result(extract<const Copyable&>(copyable)()); > > > > > >> > > > > > >> > > > > > >> HTH > > > > > >> > > > > > >> Jim > > > > > > > > > > > > > > >
_______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig