xZA
xZA

Reputation: 153

Cython: Pass by Reference

Problem

I would like to pass a vector by reference to a function in Cython.

cdef extern from "MyClass.h" namespace "MyClass":
    void MyClass_doStuff "MyClass::doStuff"(vector[double]& input) except +

cdef class MyClass:

...

@staticmethod
def doStuff(vector[double]& input):
    MyClass_doStuff(input)

Question

The above code doesn't throw an error during compilation but it's also not working. input is simply unchanged after the method. I have also tried the recommendation in this question but in this case the cdef-function won't be accessible from Python ("unknown member doStuff...").

Is passing by reference possible and, if so, how to do it properly?

Edit

This is not a duplicate of cython-c-passing-by-reference as I refer to the question in the section above. The proposed solution does not accomplish my goal of having a python function taking a parameter by reference.

Upvotes: 4

Views: 3303

Answers (1)

DavidW
DavidW

Reputation: 30901

The problem

The trouble, as Kevin and jepio say in the comments to your question, is how you handle the vector in Python. Cython does define a cpp vector class, which is automatically converted to/from a list at the boundary to Cython code.

The trouble is that conversion step: when your function is called:

def doStuff(vector[double]& input):
    MyClass_doStuff(input)

is transformed to something close to

def doStuff(list input):
    vector[double] v= some_cython_function_to_make_a_vector_from_a_list(input)
    MyClass_doStuff(input)
    # nothing to copy the vector back into the list

The answer(s)

I think you have two options. The first would be to write the process out in full (i.e. do two manual copies):

def doStuff(list input):
  cdef vector[double] v = input
  MyClass_doStuff(v)
  input[:] = v

This will be slow for large vectors, but works for me (my test function is v.push_back(10.0)):

>>> l=[1,2,3,4]
>>> doStuff(l)
>>> l
[1.0, 2.0, 3.0, 4.0, 10.0]

The second option is to define your own wrapper class that directly contains a vector[double]

cdef class WrappedVector:
  cdef vector[double] v
  # note the absence of:
  #   automatically defined type conversions (e.g. from list)
  #   operators to change v (e.g. [])
  #   etc.
  # you're going to have to write these yourself!

and then write

def doStuff(WrappedVector input):
  MyClass_doStuff(input.v)

Upvotes: 3

Related Questions