Skip to content
Advertisement

How to make the elements of a NumPy array property settable?

I have a property of a Python object that returns an array. Now, I can set the setter of that property such that the whole array is settable. However, I’m missing how to make the elements by themselves settable through the property.

I would expect from a user perspective (given an empty SomeClass class):

>>> x = SomeClass()
>>> x.array = [1, 2, 3]
>>> x.array[1] = 4
>>> print (x.array)
[1, 4, 3]

Now, suppose that SomeClass.array is a property defined as

class SomeClass(object):
    def __init__(self, a):
        self._a = a

    @property
    def array(self):
        return self._a
    @array.setter
    def array(self, a):
        self._a = a

Everything still works as above. Also if I force simple NumPy arrays on the setter.

However, if I replace the return self._a with a NumPy function (that goes in a vectorised way through the elements) and I replace self._a = a with the inverse function, of course the entry does not get set anymore.

Example:

import numpy as np

class SomeClass(object):
    def __init__(self, a):
        self._a = np.array(a)

    @property
    def array(self):
        return np.sqrt(self._a)
    @array.setter
    def array(self, a):
        self._a = np.power(a, 2)

Now, the user sees the following output:

>>> x = SomeClass([1, 4, 9])
>>> print (x.array)
array([1., 2., 3.])
>>> x.array[1] = 13
>>> print (x.array)    # would expect an array([1., 13., 3.]) now!
array([1., 2., 3.])

I think I understand where the problem comes from (the array that NumPy creates during the operation gets its element changed but it doesn’t have an effect on the stored array).

What would be a proper implementation of SomeClass to make single elements of the array write-accessible individually and thus settable as well?

Thanks a lot for your hints and help, TheXMA

The points @Jaime made below his answer helped me a lot! Thanks!

Advertisement

Answer

Since arrays are mutable objects, the individual items are settable even without a setter function:

>>> class A(object):
...     def __init__(self, a):
...         self._a = np.asarray(a)
...     @property
...     def arr(self):
...         return self._a
...
>>> a = A([1,2,3])

>>> a.arr
array([1, 2, 3])

>>> a.arr = [4,5,6] # There is no setter...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

>>> a.arr[1] = 7 # ...but the array is mutable
>>> a.arr
array([1, 7, 3])

This is one of the uses of tuples vs. lists, since the latter are mutable, but the former aren’t. Anyway, to answer your question: making individual items settable is easy, as long as your getter returns the object itself.

The fancier performance in your second example doesn’t seem easy to get in any simple way. I think you could make it happen by making your SomeClass.array attribute be a custom class, that either subclasses ndarray or wraps an instance of it. Either way would be a lot of nontrivial work.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement