Boost logo

Boost :

From: Donavon Keithley (keithley_at_[hidden])
Date: 2001-05-04 17:02:00


I'm experimenting with a binary tree structure using polymorphic nodes, but
I seem to be losing object identity on the Python side.

        struct BaseNode
        {
          BaseNode* l;
          BaseNode* r;
        };

        struct DerivedNode : public BaseNode
        {
          int foo;
        };

Following the cookbook, I wrap BaseNode* as follows:

        PyObject* to_python(BaseNode* p)
        {
          return
python::python_extension_class_converters<BaseNode>::smart_ptr_to_python(p);
        }
        PyObject* to_python(const BaseNode* p)
        {
          return to_python(const_cast<BaseNode*>(p));
        }

Similarly for DerivedNode. And then build the classes like so:

        boost::python::class_builder<BaseNode> BaseNode_class(this_module,
"BaseNode");
        BaseNode_class.def(boost::python::constructor<>());
        BaseNode_class.def_read_write(&BaseNode::l, "l");
        BaseNode_class.def_read_write(&BaseNode::r, "r");

        boost::python::class_builder<DerivedNode> DerivedNode_class(this_module,
"DerivedNode");
        DerivedNode_class.def(boost::python::constructor<>());
        DerivedNode_class.def_read_write(&DerivedNode::foo, "foo");
        DerivedNode_class.declare_base(BaseNode_class, python::without_downcast);

In Python:

>>> dn0 = DerivedNode()
>>> dn0.foo = 0
>>> dn1 = DerivedNode()
>>> dn1.foo = 1
>>> dn0.l = dn1
>>> dn0.l
<BaseNode object at 00D46540> <-- Uh oh...
>>> dn0.l.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: foo

This clearly doesn't work, so my question is what would be a correct
approach?

I've noticed -- and this is probably related -- that if I instantiate
BaseNodes, it sort of works:

>>> bn0 = BaseNode()
>>> bn1 = BaseNode()
>>> bn0.l = bn1

I've verified that bn0.l and bn1 refer to the same instance of BaseNode on
the C++ side, in spite of the fact that their Python identities are not the
same:

>>> id(bn0.l)
13919552
>>> id(bn1)
13920016

I only barely understand how BPL works under the hood, but it seems that
what I need here is proxies on the Python side -- that is, a to_python
conversion that always returns the same PyObject for the same BaseNode* or
DerivedNode*.

Any insight would be greatly appreciated!
--Donavon


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk