0

Getters and setters seem to behave weirdly when performing += with numpy arrays due to in-place mutation: a += b behaves differently from a = b + a when b is a numpy array.

A minimal example is the following class (note that the setter does not modify _x in order to show that the act of setting _x is not needed to achieve this behavior):

class Foo:
    def __init__(self,x_val):
        self._x = x_val
    
    @property
    def x(self):
        return self._x
    
    @x.setter
    def x(self, new_x):
        print(f'old_x = {self._x}; new_x = {new_x}')

The following works correctly, where the instance variable is an integer:

a = Foo(2)
print(a.x)  # Prints: 2
a.x = a.x + 2  # Prints: old_x = 2; new_x = 4
print(a.x)  # Prints: 2
a.x += 2  # Prints: old_x = 2; new_x = 4
print(a.x)  # Prints: 2

But when the instance variable is a numpy array, += differs from + (!)

import numpy as np

b = Foo(np.array([1, 2]))
print(b.x)  # Prints: [1 2]
b.x = np.array([1, 2]) + b.x  # Prints: old_x = [1 2]; new_x = [2 4]
print(b.x)  # Prints: [1 2]
b.x += np.array([1, 2])  # Prints: old_x = [2 4]; new_x = [2 4]
print(b.x)  # Prints: [2 4]

It looks as though += is modifying the b._x array object it got in place, after addition, too! This seems like a strange default for numpy's __iadd__() function to have. How do I get b.x += y to work like b.x = y + b.x? Must @property's always output copies of objects that implement __iadd__() to prevent this from happening? Is it a bug in numpy?

Python version: 3.7.13

Numpy version: 1.21.5

wjandrea
  • 28,235
  • 9
  • 60
  • 81
abeta201
  • 233
  • 1
  • 14
  • 1
    Probably good to read the [original motivation for adding the augmented assignment operators to the language](https://peps.python.org/pep-0203/) – juanpa.arrivillaga Jun 28 '23 at 22:27
  • No, but upon finishing writing this question, I think this answer does: https://stackoverflow.com/questions/35910577/why-does-python-numpys-mutate-the-original-array. I'll mark it as duplicate – abeta201 Jun 28 '23 at 22:27

0 Answers0