I created a Pixel class for image processing (and learn how to build a class). A full image is then a 2D numpy.array of Pixel but when I added a __getattr__
method , it stopped to work, because numpy wants an __array_struct__
attribute.
I tried to add this in __getattr__
:
if name == '__array_struct__':
return object.__array_struct__
Now it works but I get
'''DeprecationWarning: An exception was ignored while fetching the attribute __array__
from an object of type 'Pixel'. With the exception of AttributeError
NumPy will always raise this exception in the future. Raise this deprecation warning to see the original exception. (Warning added NumPy 1.21)
I = np.array([Pixel()],dtype = Pixel)'''
a part of the class:
class Pixel:
def __init__(self,*args):
#things to dertermine RGB
self.R,self.G,self.B = RGB
#R,G,B are float between 0 and 255
...
def __getattr__(self,name):
if name == '__array_struct__':
return object.__array_struct__
if name[0] in 'iI':
inted = True
name = name[1:]
else:
inted = False
if len(name)==1:
n = name[0]
if n in 'rgba':
value = min(1,self.__getattribute__(n.upper())/255)
elif n in 'RGBA':
value = min(255,self.__getattribute__(n))
assert 0<=value
else:
h,s,v = rgb_hsv(self.rgb)
if n in 'h':
value = h
elif n == 's':
value = s
elif n == 'v':
value = v
elif n == 'S':
value = s*100
elif n == 'V':
value = v*100
elif n == 'H':
value = int(h)
if inted:
return int(value)
else:
return value
else:
value = []
for n in name:
try:
v = self.__getattribute__(n)
except AttributeError:
v = self.__getattr__(n)
if inted:
value.append(int(v))
else:
value.append(v)
return value
CodePudding user response:
Your class should either implement __array__
or raise an AttributeError
when numpy tries to get it. The warning message says you raised some other error and that numpy will not accept that in the future. I haven't figured out your code well enough to know, but it could be that calling self.__getattr__(n)
inside of __getattr__
hits a maximum recursion error.
object.__array_struct__
doesn't exist and so just by luck its AttributeError
exception is what numpy was looking for. A better strategy is to raise AttributeError
for anything that doesn't meet the selection criteria for your automatically generated attributes. Then you can take out the special case for __array_struct__
that doesn't work properly anyway.
CodePudding user response:
When you are in a class method and want a fallback, fall back to the same method on the super()
proxy:
import numpy as np
class Pixel:
def __init__(self, value):
self.value = value
def __getattr__(self, name):
print(f"{name!r} was requested for {self}")
return super().__getattr__(name)
I = np.array([Pixel(1), Pixel(2)], dtype=Pixel)
'__array_struct__' was requested for <__main__.Pixel object at 0x7f6ccc40e970>
'__array_interface__' was requested for <__main__.Pixel object at 0x7f6ccc40e970>
'__array__' was requested for <__main__.Pixel object at 0x7f6ccc40e970>
'__array_struct__' was requested for <__main__.Pixel object at 0x7f6ccc40e910>
'__array_interface__' was requested for <__main__.Pixel object at 0x7f6ccc40e910>
'__array__' was requested for <__main__.Pixel object at 0x7f6ccc40e910>