Tam Coton Tam Coton - 1 month ago 7
Python Question

__getitem__ and __setitem__ not being called

I have the following class definition:

class Codes():
def __new__(self, inp):
self.data = np.zeros((50,50))
self.capacity = 50
self.size = 6
self.data[:self.size,:self.size] = inp
self.x = 0
self.y = 0

return self

def __setitem__(self,coords,value):
x = coords[0]
y = coords[1]
if max(x,y) >= self.capacity:
self.capacity *= 2
newdata = np.zeroes((self.capacity,))
newdata[:self.size,:self.size] = self.data
self.data = newdata

self.data.__setitem__(coords,value)

if max(x,y) >= self.size:
print("expanding")
self.size = max(x,y)
print ("Debug")
def __getitem__(self,coords):
x = coords[0]
y = coords[1]
return self.data[x,y]


The get and set methods don't seem to be being called. I'm initialising with:

inp = np.array([[20151125,18749137,1728984,30943339,10071777,33511524],
[31916031,21629792,16929656,7726640,15514188,4041754],
[16080970,8057251,1601130,7981243,11661866,16474243],
[24592653,32451966,21345942,9380097,10600672,31527494],
[77061,17552253,28094349,6899651,9250759,31663883],
[33071741,6796745,25397450,24659492,1534922,27995004]])
a = Codes(inp)


If I try to then execute
print(a[1,1])
, I get the error:

Traceback (most recent call last):
File "C:/Users/cotont/Dropbox/Advent of Code/Advent of Code 25-1.py", line 55, in <module>
print(a[1,1])
TypeError: 'type' object is not subscriptable


If I try to execute
a[49,49] = 1
, I get:

Traceback (most recent call last):
File "C:/Users/cotont/Dropbox/Advent of Code/Advent of Code 25-1.py", line 55, in <module>
a[49,49] = 1
TypeError: 'type' object does not support item assignment


Why are my custom methods not being called, and how do I fix it?

Answer

You are misunderstanding what __new__ does or accidentally used it where you should have used __init__. You are returning the Codes object itself by returning self:

def __new__(self, inp):
    # ...
    return self

__new__ is called as a static method on the class and is expected to produce a new instance in the method.

Because you returned the type object (the class), __getitem__ and __setitem__ are looked up on type (the default metaclass) (see Special method lookup), which fails.

You probably wanted to use __init__ there instead; __init__ is called on an already-created instance:

class Codes():
    def __init__(self, inp):
        self.data = np.zeros((50,50))
        self.capacity = 50
        self.size = 6
        self.data[:self.size,:self.size] = inp
        self.x = 0
        self.y = 0

__init__ doesn't need to return anything (and what it returns is ignored anyway), so you can drop the return self line altogether.

If you feel you must use __new__ (perhaps because you are subclassing an immutable type), then at the very least create an instance with super().__new__():

class Codes():
    def __new__(cls, inp):
        instance = super(Codes, cls).__new__(cls)
        instance.data = np.zeros((50,50))
        instance.capacity = 50
        instance.size = 6
        instance.data[:self.instance,:instance.size] = inp
        instance.x = 0
        instance.y = 0
        return instance

but using __init__ instead is just simpler.

Comments