[C++-sig] Pointer to existing Python object
Andreas Beyer
beyer at imb-jena.de
Fri May 20 19:47:52 CEST 2005
Ok, I'll try it again:
The code of my initial posting is already an example for what I am
trying to outline here. If you understood the issues related with it,
stop reading here.
Assume you have two C++ classes A and B. Objects of A are stored in B (B
is a container). You also have a C++ factory class, for simplicity lets
assume this too is B, i.e. objects of kind A get created by B objects
(in C++ code). When you now send instances of A back and forth between
your python code and the container B, you would like to always have the
same python wrapper around your As whenever the C++ instances are the
same. This worked already when you initially created the objects in
python and then stored them in the C++ container. However, it failed for
instances created by factory objects that get placed in the container
before(!) the newly created objects are returned to the python
environment. That means: when you retreive the same C++ object twice you
would get two different python wrappers around the same C++ object.
There is no harm in this as long as you don't use the python wrappers
for anything else than accessing the underlying C++ object. But already
comparison might fail (unless you overwrite the == operator). Thus in
python:
>>> b = B() # make a container/factory
>>> a1 = b.get() # get one wrapper for a contained in b
>>> a2 = b.get() # try to get the *same* object
>>> assert(a1 == a2) # will fail
In this example a1 and a2 will refer to the same underlying C++
instance, but the wrappers are different. The technical problem is:
boost::python does not 'know' that there is already an existing wrapper
a1 when you call get() for the second time. (David, correct my if I'm
wrong.)
The sollution suggested by David is to create a temporary python wrapper
in the C++ wrapper code. After that, the boost::python wizardry will
remember the smart pointer (always use smart pointers in this business!)
and return the same python wrapper for instances of A.
See here http://mail.python.org/pipermail/c++-sig/2005-April/008849.html
and here http://mail.python.org/pipermail/c++-sig/2005-May/008910.html
for the solution.
After aplying these changes you not only can compare the python
instances as shown above, but you can even modify the wrappers
themselve, e.g. by adding new (python) attributes.
Comparison must work if you use instances of A as keys in a python dict.
If you only need comparison to work properly it might also be possible
to define __cmp__() in your wrapper code. I haven't tested this option,
but I don't see why it shouldn't work.
Finally, just to be very explicit:
You don't need to consider all this stuff if either
- you don't have C++ code where instances get placed in a container
inside C++ before returning them to the python interpreter
or
- you *only* need the python wrapper to inspect/modify the underlying
C++ instance.
Hope this is better understandable.
Andreas
David Abrahams wrote:
>Andreas Beyer <beyer at imb-jena.de> writes:
>
>
>
>>I think this is a very strong concept of general interest: I can now
>>change Python attributs of wrappers (such as adding attributs in
>>Python), although the objects were created and are managed by C++
>>code. (By management I mean live-time management.) There is no
>>difficulty if you get an object from a C++ factory class and store
>>it in a Python container. However, I want to store it in a C++
>>container. In general, the two classes (the container and the
>>factory) can of course be distinct. I don't think David's sollution
>>is affected by this.
>>
>>
>
>If you think there is something here of general interest, you might
>want to rephrase that. I _think_ I understand what you're saying, but
>I'm not sure that others will.
>
>
>
>
More information about the Cplusplus-sig
mailing list