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.