[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