[C++-sig] C++ const -> Python immutable?

Philip Austin paustin at eos.ubc.ca
Wed Sep 25 22:41:26 CEST 2002


Ralf W. Grosse-Kunstleve writes:
 > 
 > Now it seems to me that both by_reference and by_const_reference
 > work, but that the "const" is lost. Is this correct?  Ralf


This is one step further than I've managed to get, and I'm wondering
whether someone could point out the errors in the following program,
or suggest another approach.  The goal is to have a simple wrapper
(numhandle) that holds an object containing a PyArrayObject*.  Given
any python sequence, numpy can produce a deep copy with:

a) PyArray_CopyFromObject(o,PyArray_NOTYPE,0,0)))

and  either an incremented reference or a deep
copy with:

b) PyArray_ContiguousFromObject(o,PyArray_NOTYPE,0,0)))

Below I try to invoke a) with the function:

numhandle pass_by_value(numhandle theArray)

and b) with 

numhandle pass_by_reference(numhandle& theArray)

(I also try to return a reference, but instantiating
numhandle_to_python_reference() causes the compiler
to complain as noted on the line tagged Error: below).

The code compiles, but the results aren't what
I expect viz:

In python:

import Numeric as N
import num_test_ext as nt
thearray=N.arange(3,typecode=N.Float32)
print "python calls pass by value"
print nt.pass_by_value(thearray)

produces:

python calls pass by value
inside reference constructor
inside pass_by_value[ 999.    1.    2.]

i.e.  the reference constructor is called, even though
the signature is:

numhandle pass_by_value(numhandle theArray)

Next I try calling:

numhandle pass_by_reference(numhandle& theArray)

in python:

print "python calls pass by reference"
print nt.pass_by_reference(thearray)

which yields:

python calls pass by reference
Traceback (most recent call last):
  File "<stdin>", line 12, in ?
TypeError: bad argument type for built-in operation


Many thanks, Phil Austin


numhandle.cpp:__________________________________

#include <boost/python/def.hpp>
#include <boost/python/module_init.hpp>
#include <boost/python/object_core.hpp>
#include <iostream>
#include <Numeric/arrayobject.h>


using namespace boost::python;

struct numhandle {
  object pyholder;
};

struct register_numhandle_from_python_by_value
{
  register_numhandle_from_python_by_value()
  {
    converter::registry::insert(&convertible, 
                       &construct, type_id<numhandle>());
  }

  static void* convertible(PyObject* o)
  {
    std::cout << "inside value convertible check" << std::endl;
    if (!PySequence_Check(o)){
      return NULL;
    }
    return o;
  }

  static void construct (PyObject* o, 
                          converter::rvalue_from_python_stage1_data* data)
  {  
    std::cout << "inside value constructor" << std::endl;
    void* storage = ((converter::rvalue_from_python_storage<numhandle>*)
                                data)->storage.bytes;
    
    object newo(detail::new_reference(
                    PyArray_CopyFromObject(o,PyArray_NOTYPE,0,0)));
    new (storage) numhandle();
    data->convertible = storage;
    numhandle& result = *((numhandle*) storage);
    result.pyholder=newo;
  }

};

struct register_numhandle_from_python_by_reference
{
  register_numhandle_from_python_by_reference()
  {
    converter::registry::insert(&convertible, 
                    &construct, type_id<numhandle&>());
  }

  static void* convertible(PyObject* o)
  {
    if (!PySequence_Check(o)){
      return NULL;
    }
    return o;
  }

  static void construct (PyObject* o, 
                          converter::rvalue_from_python_stage1_data* data)
  {  
    std::cout << "inside reference constructor" << std::endl;
    void* storage = ((converter::rvalue_from_python_storage<numhandle>*)
                                data)->storage.bytes;
    
    object newo(detail::new_reference(
                    PyArray_ContiguousFromObject(o,PyArray_NOTYPE,0,0)));
    new (storage) numhandle();
    data->convertible = storage;
    numhandle& result = *((numhandle*) storage);
    result.pyholder=newo;
  }

};


struct numhandle_to_python_value : 
                to_python_converter<numhandle, numhandle_to_python_value>
{
  static PyObject*
  convert(numhandle x)
  {
    return incref(x.pyholder.ptr());
  }
};

struct numhandle_to_python_reference : 
                to_python_converter<numhandle&, numhandle_to_python_reference>
{
  static PyObject*
  convert(numhandle& x)
  {
    return incref(x.pyholder.ptr());
  }
};

numhandle pass_by_reference(numhandle& theArray){
  float* thedata= (float*)  ((PyArrayObject*) theArray.pyholder.ptr())->data;
  thedata[0]=888.;
  std::cout << "inside pass_by_reference";
  return theArray;
}

numhandle pass_by_value(numhandle theArray){
  float* thedata= (float*)  ((PyArrayObject*) theArray.pyholder.ptr())->data;
  std::cout << "inside pass_by_value";
  thedata[0]=999.;
  return theArray;
}


numhandle& return_a_reference(numhandle& theArray){
  float* thedata= (float*)  ((PyArrayObject*) theArray.pyholder.ptr())->data;
  std::cout << "return a reference";
  thedata[0]=777.;
  return theArray;
}

BOOST_PYTHON_MODULE_INIT(num_test_ext)
{ 
  using namespace boost::python;
  import_array();
  register_numhandle_from_python_by_value();
  register_numhandle_from_python_by_reference();
  numhandle_to_python_value();

  //Error: the following won't compile, error 
  // message says  "forming
  //   pointer to reference type `numhandle& const"

  //numhandle_to_python_reference();

  def("pass_by_reference", pass_by_reference);
  def("pass_by_value", pass_by_value);
}






More information about the Cplusplus-sig mailing list