How about class_<...>.enable_copy() ?
Hi! I often use copy.[deep]copy() to copy python objects / BPL-exported types. This works if pickling support has been explicitly coded, by pickling and unpickling. It would be neat if there was an .enable_copy() or sth. like that, which would define a __copy__ (or __deepcopy__) method that simply calls the copy constructor. That would be more efficient than the pickling approach, both at runtime and in terms of saved LOCs. Have you thought about such a thing? Is there a common short idiom that does that already? Is there a rationale for not providing copying support? -- Ciao, / / /--/ / / ANS
Hi again! Am Freitag, 08. Juni 2007 17:06:36 schrieb Hans Meine:
I often use copy.[deep]copy() to copy python objects / BPL-exported types. This works if pickling support has been explicitly coded, by pickling and unpickling.
Oh, and BTW, there is a related thing that bugs me: When I copy.copy() a BPL exported type with pickling support and __getstate_manages_dict__ set, I get two objects with *the same* __dict__: In [15]: cm.__dict__ Out[15]: {} In [16]: cm2 = copy.copy(cm) In [17]: cm.foo = 42 In [18]: cm2.foo Out[18]: 42 That looks like a bug to me, and pickle3.cpp also does not copy the __dict__. Oh, but it uses update().. maybe that should be put into the docs. From pickle3.cpp:
// restore the object's __dict__ dict d = extract<dict>(w_obj.attr("__dict__"))(); d.update(state[0]);
I suggest to add a sentence in the "Practical Advice" section:
If __getstate__ is required, include the instance's __dict__ in the Python object that is returned**BEGIN**, and use the dict to update() your __dict__ in __setstate__**END**.
Also, above it says:
To resolve this problem, it should first be established that the __getstate__ and __setstate__ methods manage the instances's __dict__ correctly. without defining "correctly". ;-)
-- Ciao, / / /--/ / / ANS
Hi! I still have the same problem as last time, that I want to be able to copy.copy(foo) and copy.deepcopy(foo) my BPL-exported objects: Am Freitag, 08. Juni 2007 17:06:36 schrieb Hans Meine:
This works if pickling support has been explicitly coded, by pickling and unpickling. It would be neat if there was an .enable_copy() or sth. like that, which would define a __copy__ (or __deepcopy__) method that simply calls the copy constructor. That would be more efficient than the pickling approach, both at runtime and in terms of saved LOCs. Have you thought about such a thing? Is there a common short idiom that does that already? Is there a rationale for not providing copying support?
Ralf answered (thanks BTW) that I should export the copy constructor. I think that is not a bad idea, but I would ideally like to have: foo = Foo(other) # copy constructor as in C++ (1) foo = copy.copy(other) # pythonic copying (2) foo = copy.deepcopy(other) # deepcopying (3) (1) is easy to do by exporting the copy constructor (2) could be implemented by setting __copy__ to the above copy constructor, but one would assume __dict__ to be (non-deep)copied, too. (3) definitely needs its own implementation, which needs to call deepcopy recursively. I would still believe that an .enable_copy() would be very handy. It could possibly be controlled by an enum arg which of the above methods should be exported. I tried to implement (2) and (3) manually today, but failed. Mostly because I am not 100% sure how to mix Python C API and BPL code correctly. I have the following general questions: A) How do I convert a Foo * into a boost::python::object if I exported the Foo class? Back in those days when I first used BPLv2, I wrote the following "nifty" function: template<class T> inline PyObject * managingPyObject(T *p) { return typename manage_new_object::apply<T *>::type()(p); } Is there a better way? Also, this only gives me a PyObject *, which brings me to my next question: B) How do I convert PyObject * into a boost::python::object if it's a new reference? Is this boost::python::detail::new_reference? Why is this in "detail" then? C) How do I convert PyObject * into a boost::python::object if it's a borrowed reference? I guess that handle(borrowed(...)) helps here? Finally, I wonder whether nobody else tried to implement __deepcopy__ with BPL yet - I could not find anything useful, searching the WWW for >2 hours now. I tried to get the copy.deepcopy function which I need to call recursively like this: PyObject* pyDeepcopy = PyRun_String("import copy\ncopy.deepcopy", Py_file_input, Py_None, Py_None); ... bp::extract<bp::dict>(result.attr("__dict__"))().update( bp::call<bp::dict>(pyDeepcopy, map.attr("__dict__"), memo)); Unfortunatly, with empty globals and locals, __import__ is not found. :-( Probably I should use PyImport_ImportModule or the new boost::python::import. That seems to work, but the recursive call then fails: File "/software/python-2.4.4/lib/python2.4/copy.py", line 185, in deepcopy y = copier(x, memo) TypeError: No to_python (by-value) converter found for C++ type: boost::python::api::proxy<boost::python::api::attribute_policies> The code (which relies on 1.34.0) now looks like this (see attachment): bp::object Foo__deepcopy__(bp::object foo, bp::dict memo) { bp::object copyMod = bp::import("copy"); bp::object deepcopy = copyMod.attr("deepcopy"); Foo *newFoo(new Foo(bp::extract<const Foo &>(foo))); bp::object result(bp::detail::new_reference(managingPyObject(newFoo))); bp::extract<bp::dict>(result.attr("__dict__"))().update( deepcopy(foo.attr("__dict__"), memo)); return result; } -- Ciao, / / /--/ / / ANS
I'm not sure why I'm getting this error from the follownig code? // data member from sig_zapv class std::vector<C4::ZEE::zap> zaps_; //boost python wrapper part class_<sig_zapv, bases<params> >("sig_zapv") .def(init<>()) .def(vector_indexing_suite<std::vector<C4::ZEE::zap>
());
//error ../../SDK/boost_1_33_1/boost/python/with_custodian_and_ward.hpp: In static member function `static PyObject* boost::python::with_custodian_and_ward_postcall<custodian, ward, BasePolicy_>::postcall(const ArgumentPackage&, PyObject*) [with ArgumentPackage = PyObject*, unsigned int custodian = 0, unsigned int ward = 1, BasePolicy_ = boost::python::default_call_policies]': ../../SDK/boost_1_33_1/boost/python/detail/caller.hpp:201: instantiated from `PyObject* boost::python::detail::caller_arity<1>::impl<F, Policies, Sig>::operator()(PyObject*, PyObject*) [with F = boost::python::objects::iterator_range<boost::python::return_internal_reference<1, boost::python::default_call_policies>, __gnu_cxx::__normal_iterator<C4::ZEE::zap*, std::vector<C4::ZEE::zap, std::allocator<C4::ZEE::zap>
::next, Policies = boost::python::return_internal_reference<1, boost::python::default_call_policies>, Sig = boost::mpl::vector2<C4::ZEE::zap&, boost::python::objects::iterator_range<boost::python::return_internal_reference<1, boost::python::default_call_policies>, __gnu_cxx::__normal_iterator<C4::ZEE::zap*, std::vector<C4::ZEE::zap, std::allocator<C4::ZEE::zap> &>]' ../../SDK/boost_1_33_1/boost/python/object/py_function.hpp:38: instantiated from `PyObject* boost::python::objects::caller_py_function_impl<Caller>::operator()(PyObject*, PyObject*) [with Caller = boost::python::detail::caller<boost::python::objects::iterator_range<boost::python::return_internal_reference<1, boost::python::default_call_policies>, __gnu_cxx::__normal_iterator<C4::ZEE::zap*, std::vector<C4::ZEE::zap, std::allocator<C4::ZEE::zap> ::next, boost::python::return_internal_reference<1, boost::python::default_call_policies>, boost::mpl::vector2<C4::ZEE::zap&, boost::python::objects::iterator_range<boost::python::return_internal_reference<1, boost::python::default_call_policies>, __gnu_cxx::__normal_iterator<C4::ZEE::zap*, std::vector<C4::ZEE::zap, std::allocator<C4::ZEE::zap> &> >]' ../../SDK/boost_1_33_1/boost/python/object/make_instance.hpp:32: instantiated from here ../../SDK/boost_1_33_1/boost/python/with_custodian_and_ward.hpp:87: warning: comparison of unsigned expression < 0 is always false make[1]: *** [wrapper.o] Error 1
____________________________________________________________________________________ Building a website is a piece of cake. Yahoo! Small Business gives you all the tools to get online. http://smallbusiness.yahoo.com/webhosting
On 7/23/07, Tim Spens <t_spens@yahoo.com> wrote:
I'm not sure why I'm getting this error from the follownig code?
// data member from sig_zapv class std::vector<C4::ZEE::zap> zaps_;
What is the definition of zap? -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
zap is a class with some getter and setter functions and some protected data members. --- Roman Yakovenko <roman.yakovenko@gmail.com> wrote:
On 7/23/07, Tim Spens <t_spens@yahoo.com> wrote:
I'm not sure why I'm getting this error from the follownig code?
// data member from sig_zapv class std::vector<C4::ZEE::zap> zaps_;
What is the definition of zap?
-- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ _______________________________________________ C++-sig mailing list C++-sig@python.org http://mail.python.org/mailman/listinfo/c++-sig
____________________________________________________________________________________ Pinpoint customers who are looking for what you sell. http://searchmarketing.yahoo.com/
On 7/24/07, Tim Spens <t_spens@yahoo.com> wrote:
zap is a class with some getter and setter functions and some protected data members.
I reviewed one more time your message and I found a few things I don't understand. You export of class vector looks strange: your code class_<sig_zapv, bases<params> >("sig_zapv") .def(init<>()) .def(vector_indexing_suite<std::vector<C4::ZEE::zap>
());
the code from tutorials( http://boost.org/libs/python/doc/v2/indexing.html ) class_<std::vector<X> >("XVec") 1^^^^^^^^ .def(vector_indexing_suite<std::vector<X> >()) 2^^^^^^^^^ ; Do you see the difference? Same class is used in both cases. -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/
Hi again! I got it working now! (Still, I would be glad if you answered my questions from my last mail and told me of possible better ways to achieve this.) On Montag 23 Juli 2007, Hans Meine wrote:
foo = Foo(other) # copy constructor as in C++ (1) foo = copy.copy(other) # pythonic copying (2) foo = copy.deepcopy(other) # deepcopying (3)
(1) is easy to do by exporting the copy constructor
(2) could be implemented by setting __copy__ to the above copy constructor, but one would assume __dict__ to be (non-deep)copied, too.
(3) definitely needs its own implementation, which needs to call deepcopy recursively.
I would still believe that an .enable_copy() would be very handy. It could possibly be controlled by an enum arg which of the above methods should be exported.
I tried to implement (2) and (3) manually today, but failed. [...] File "/software/python-2.4.4/lib/python2.4/copy.py", line 185, in deepcopy y = copier(x, memo) TypeError: No to_python (by-value) converter found for C++ type: boost::python::api::proxy<boost::python::api::attribute_policies>
Obviously, there was another extract<dict> missing, since attr("__dict__") does not deliver an object, but this strange proxy. OTOH, passing the proxy to update() in __copy__ works?! Maybe someone is interested in turning my code into a standard BPL facility? (BTW: Is __dict__ created on demand? Then one should probably add a guard to both my __copy__ and __deepcopy__.) On Montag 23 Juli 2007, Hans Meine wrote:
Probably I should use PyImport_ImportModule or the new boost::python::import.
Speaking of the latter, shouldn't the python:: prefix be removed from the code within boost_1_34_0/libs/python/src/import.cpp ? I recently had syntax errors from GCC-4.1.2 within kdelibs-3.5.7 with a similar case:
namespace KABC {
class KABC_EXPORT Field { public: virtual QString value( const KABC::Addressee & );
Here, I had to remove KABC:: in order to let it compile. (Which I found surprising, but anyways.) Ciao, / / .o. /--/ ..o / / ANS ooo
Hi again! Anyone cares to comment on my older posting? On Montag 23 Juli 2007, Hans Meine wrote:
On Montag 23 Juli 2007, Hans Meine wrote:
foo = Foo(other) # copy constructor as in C++ (1) foo = copy.copy(other) # pythonic copying (2) foo = copy.deepcopy(other) # deepcopying (3)
(1) is easy to do by exporting the copy constructor
(2) could be implemented by setting __copy__ to the above copy constructor, but one would assume __dict__ to be (non-deep)copied, too.
(3) definitely needs its own implementation, which needs to call deepcopy recursively.
I would still believe that an .enable_copy() would be very handy. It could possibly be controlled by an enum arg which of the above methods should be exported.
Here is the updated, perfectly working code for (2) and (3), which I propose to be included in BPL. Also, some things appear hackish to me -- I would be glad to get feedback on how to do this in a more "standard" way: a) wrap a pointer to a newly created object in a bp::object -- there must be a shorter/better way than bp::detail::new_reference(typename manage_new_object::apply<T *>::type()(p) no? b) shouldn't a 64bit-safe version of inline id(object) { return (int)(copyable.ptr()); } be added to boost::python? c) is my solution of accessing copy/deepcopy improvable? (I guess not - it looks already quite OK to me.) d) would you use the visitor pattern, i.e. class_<T>::enable_copy for the above code? AFAICS, there are two small advantages: * both functions can be def'd in one line * the type does not have to be repeated, but is fetched from the class_<> template instance
Maybe someone is interested in turning my code into a standard BPL facility? (BTW: Is __dict__ created on demand? Then one should probably add a guard to both my __copy__ and __deepcopy__.)
I'd like to get an authoritive answer on this - do BPL-exported objects always have a __dict__, or is it only created on demand/access?
On Montag 23 Juli 2007, Hans Meine wrote:
Probably I should use PyImport_ImportModule or the new boost::python::import.
Speaking of the latter, shouldn't the python:: prefix be removed from the code within boost_1_34_0/libs/python/src/import.cpp ? I recently had syntax errors from GCC-4.1.2 within kdelibs-3.5.7 with a similar case:
namespace KABC {
class KABC_EXPORT Field { public: virtual QString value( const KABC::Addressee & );
Here, I had to remove KABC:: in order to let it compile. (Which I found surprising, but anyways.)
This is not very much related, but interesting. -- Ciao, / / .o. /--/ ..o / / ANS ooo
Am Dienstag, 16. Oktober 2007 22:37:04 schrieb Hans Meine:
Here is the updated, perfectly working code for (2) and (3), which I propose to be included in BPL. Also, some things appear hackish to me -- I would be glad to get feedback on how to do this in a more "standard" way:
Ooops - of course I indented to attach something.. -- Ciao, / / /--/ / / ANS
Test reply Nothing... -----Original Message----- From: c++-sig-bounces@python.org [mailto:c++-sig-bounces@python.org] On Behalf Of Hans Meine Sent: Wednesday, October 17, 2007 4:25 PM To: Development of Python/C++ integration Subject: Re: [C++-sig] How about class_<...>.enable_copy() ? Am Dienstag, 16. Oktober 2007 22:37:04 schrieb Hans Meine:
Here is the updated, perfectly working code for (2) and (3), which I propose to be included in BPL. Also, some things appear hackish to me -- I would be glad to get feedback on how to do this in a more "standard" way:
Ooops - of course I indented to attach something.. -- Ciao, / / /--/ / / ANS
on Tue Oct 16 2007, Hans Meine <hans_meine-AT-gmx.net> wrote:
Hi again!
Anyone cares to comment on my older posting?
On Montag 23 Juli 2007, Hans Meine wrote:
On Montag 23 Juli 2007, Hans Meine wrote:
foo = Foo(other) # copy constructor as in C++ (1) foo = copy.copy(other) # pythonic copying (2) foo = copy.deepcopy(other) # deepcopying (3)
(1) is easy to do by exporting the copy constructor
(2) could be implemented by setting __copy__ to the above copy constructor, but one would assume __dict__ to be (non-deep)copied, too.
(3) definitely needs its own implementation, which needs to call deepcopy recursively.
I would still believe that an .enable_copy() would be very handy. It could possibly be controlled by an enum arg which of the above methods should be exported.
Here is the updated, perfectly working code for (2) and (3), which I propose to be included in BPL. Also, some things appear hackish to me -- I would be glad to get feedback on how to do this in a more "standard" way:
Is there a reason to have a special interface for this? Suppose we just do it unconditionally unless the person wrapping passes noncopyable to class_<...> ? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
Is there a reason to have a special interface for this? Suppose we just do it unconditionally unless the person wrapping passes noncopyable to class_<...> ?
Speaking of which, is there any good reason why boost.python shouldn't correspondingly infer noncopyability if class_metadata<...>::wrapped derives from boost::noncopyable? Alex
On Dienstag 30 Oktober 2007, David Abrahams wrote:
Here is the updated, perfectly working code for (2) and (3), which I propose to be included in BPL. Also, some things appear hackish to me -- I would be glad to get feedback on how to do this in a more "standard" way:
Is there a reason to have a special interface for this? Suppose we just do it unconditionally unless the person wrapping passes noncopyable to class_<...> ?
No; that would be even better (I originally thought about that, too). The only disadvantage I see is a bit more generated code, but I think that copying copyable objects is something that many users expect to be able to do. And for now, I really think that the possibility to disable it using noncopyable is enough; otherwise one might introduce an API for that later. -- Ciao, / / .o. /--/ ..o / / ANS ooo
participants (7)
-
Alex Mohr -
Chang Chen -
David Abrahams -
Hans Meine -
Hans Meine -
Roman Yakovenko -
Tim Spens