1

I want to subclass np.ndarray in order to create a class for 2D points with most of the Numpy machinery still available and some additional methods specific to 2D arrays. One of those methods is rotating the point around the origin. I tried that by using matrix multiplication and then assigning the data attribute of the result to my point.

>>> import numpy as np
>>> class Point2D(np.ndarray):
...     def __new__(cls, coords):
...         point = np.array(coords, dtype=float).view(cls)
...         if point.shape != (2,):
...             raise ValueError("A Point2D needs exactly two coordinates.")
...         return point
...
...     def rotate(self, angle):
...         self.data = (np.array([[np.cos(angle), -np.sin(angle)],
...                                [np.sin(angle),  np.cos(angle)]]) @ self).data
...
>>> x = Point2D((1, 0))
>>> x.rotate(np.pi/2)
__main__:10: DeprecationWarning: Assigning the 'data' attribute is an inherently unsafe operation and will be removed in the future.

The deprecation warning urges me not to assign the data attribute. What should I do instead?

2
  • The data attribute of a Numpy array provides a memoryview() of the same array. It allows raw byte-level access to the array data. You want high-level access to your elements, therefore the answer of Eric works fine. Also, as a memoryview instance is an object with methods to allow access to the data and corresponding metadata rather than the raw data itself, assigning to .data would (in general) replace the memoryview with something completely different rather than just writing to the data and thus isn't desirable in any conceivable practical case, hence the warning. Commented Mar 25, 2021 at 9:27
  • Well, actually, for regular numpys array, assigning to .data does not replace the memoryview with something else, as Numpy package code does "magic" when performing the assignment. But it will still affect other things than just the raw data and the array may behave unexpectedly henceforth. It's also not a good way of accessing .data. Not that it matters for your particular case. Just clarifying my previous comment. Commented Mar 25, 2021 at 9:42

2 Answers 2

1

You can also use ellipsis slice assignment,

self[...] = np.array([[c, -s],
                      [s,  c]]) @ self)

Where here ... is "short" for :, :.

Sign up to request clarification or add additional context in comments.

Comments

0

Use np.copyto.

>>> import numpy as np
>>> class Point2D(np.ndarray):
...     def __new__(cls, coords):
...         point = np.array(coords, dtype=float).view(cls)
...         if point.shape != (2,):
...             raise ValueError("A Vec2D needs exactly two coordinates.")
...         return point
...
...     def rotate(self, angle):
...         s = np.sin(angle)
...         c = np.cos(angle)
...         np.copyto(self, np.array([[c, -s],
...                                   [s,  c]]) @ self)
...
>>> x = Point2D((1, 0))
>>> x.rotate(np.pi/2)
>>> x
Point2D([6.123234e-17, 1.000000e+00])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.