It looks you are trying to use property in a way it wasn't intended to work. It is possible to use properties in your scenario, but from the performance point of view it might not be wise, as this answer will show further below.
In pure Python you could use (as you surely already know) properties as follows to access elements in a list:
def class A:
def __init__(self):
self._lst=[1,2,3,4]
@property
def lst(self):
return self._lst
I.e. property isn't used to access elements of the list but the list itself.
And now
a=A()
a.lst # accesses list via property
a.lst[0] = 10 # accesses list via property + __getitem__ of the list
# no property-setter needed, we don't set lst-property,
# just an element of the list
a.lst[0] # returns 10
The same idea naively translated to Cython would be (your example somewhat simplified):
%%cython
from libc.string cimport memset
cdef class CyA:
cdef int _Addr[26]
def __cinit__(self):
memset(self._Addr, 0,sizeof(int)*26)
@property
def Addr(self):
return self._Addr
However, this doesn't work as one might expect:
a=CyA()
a.Addr[0] = 10
a.Addr[0] # returns 0!
The problem is, that behind the scenes Cython converted the int C-array into a list (what an overhead!) and changing this copy of the Addr-array doesn't change the original array at all.
You need to return a (typed) memory view of array _Addr in the property:
%%cython
....
@property
def Addr(self):
cdef int[:] memview = self._Addr
return memview
Which works as expected:
a=CyA()
a.Addr[0] = 10
a.Addr[0] # returns 10, as expected!
You might be worried about overhead of creating a memory view for just one access (and you would be right), in this case it is possible to cache the created memory view and reuse it over and over again:
%%cython
cdef class CyA:
cdef int _Addr[26]
cdef int[:] memview_cache
def __cinit__(self):
memset(self._Addr, 1204,sizeof(int)*26)
self.memview_cache = None
...
@property
def Addr_fast(self):
if self.memview_cache is None:
self.memview_cache = self._Addr
return self.memview_cache
leads to a speed-up of factor 3:
a=CyA()
%timeit a.Addr # 1.05 µs ± 36.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit a.Addr_fast # 328 ns ± 13.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
This is however still too much overhead, compared to non-fancy and straight forward setting of elements via __setitem__:
%%cython
cdef class CyA:
cdef int _Addr[26]
...
def __setitem__(self, index, int value):
self._Addr[index] = value
which leads to
a=CyA()
%timeit a.Addr_fast[0] = 10 # 483 ns ± 22.2 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit a[0] = 10 # 32.5 ns ± 0.669 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
which is about 10 times faster!