14

I am new to Cython and encountered this code snippet:

import numpy as np
cimport numpy as np

testarray = np.arange(5)
cdef np.ndarray[np.int_t, ndim=1] testarray1 = testarray.copy()
cdef np.ndarray[np.float_t, ndim=1] testarray2 = testarray.astype(np.float)

During compilation, it said Buffer types only allowed as function local variables. However, I am using .copy() or .astype() which is returning not a memoryview, but a copy. Why is this still happening? How can I get around this?

Thanks!

Yuxiang Wang
  • 8,095
  • 13
  • 64
  • 95
  • 1
    `testarray` itself is a buffer. So why not put everything into a function and call it from Python? – Midnighter May 23 '14 at 21:06
  • @Midnighter Thanks! I was trying to define some global constants to save several lines of code... And I never thought that `testarray` is a buffer itself before. Thanks for the input - I'd go with more verbose code then I guess! :) – Yuxiang Wang May 23 '14 at 21:08

1 Answers1

16

When you define an array in cython using np.ndarray[Type, dim], that is accessing the python buffer interface, and those can't be set as module level variables. This is a separate issue from views vs copies of numpy array data.

Typically if I want to have an array as a module level variable (i.e not local to a method), I define a typed memoryview and then set it within a method using something like (untested):

import numpy as np
cimport numpy as np

cdef np.int_t[:] testarray1

def init_arrays(np.int_t[:] testarray):
    global testarray1
    testarray1 = testarray.copy()
JoshAdel
  • 66,734
  • 27
  • 141
  • 140
  • Thank you so much Josh! It is very helpful. However, the `memoryviewslice` would not have ndarray methods such as ndarray.mean() or ndarray.max()... Any chance you know a workaround? – Yuxiang Wang May 24 '14 at 05:19
  • 1
    As long as it doesn't incur too much overhead for what you're doing, you can use `np.asarray` to coerce the typed memoryview to a numpy array http://docs.cython.org/src/userguide/memoryviews.html#coercion-to-numpy within the method that you are using the memoryview in. – JoshAdel May 24 '14 at 13:55
  • Excellent! That is awesome functionality that I didn't notice. Thank you so much Josh! – Yuxiang Wang May 24 '14 at 18:35
  • Why do you use `testarray.copy()` instead of just `testarray1 = testarray`? – Kyle Barron May 28 '20 at 19:11
  • From https://stackoverflow.com/a/24166170, "I am using `.copy()` to guarantee that you have contiguous data in memory. This would be unnecessary if positions was Fortran-contiguous.". So I'm guessing the `copy()` here is also to ensure contiguous memory – Kyle Barron May 28 '20 at 19:14