Search code examples
pythonoopdescriptor

How do I bring instance attributes into a @staticmethod


I have a base class, like so:

class coordinates(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    @property
    def x(self):
        return self.x

    @x.setter
    def x(self, x):
        self.x = x

    @property
    def y(self):
        return self.y

    @y.setter
    def y(self, y):
        self.y = y

    @property
    def z(self):
        return self.z

    @z.setter
    def z(self, z):
        self.z = z

Then I create a child class that will inherit from coordinates, and have a static method in it, that will use instance attributes like x, y, and z ... like so:

class volume(coordinates):
    def __init__(self, x, y, z):
        super().__init__(x, y, z)
        self.volume = self.calculate_volume()

    def calculate_volume(self):
        return self.x * self.y * self.z

    @staticmethod
    def goes_through(x, y, z, h, l):
        if x < l and y < h:
            return f"Use surface {x}{y} to go through"
        elif y < l and x < h:
            return f"Use surface {y}{x} to go through"
        elif x < l and z < h:
            return f"Use surface {x}{z} to go through"
        elif z < l and x < h:
            return f"Use surface {z}{x} to go through"
        elif z < l and y < h:
            return f"Use surface {z}{y} to go through"
        elif y < l and z < h:
            return f"Use surface {y}{z} to go through"
        else:
            return "Object can't go through"

Then I instantiate an object and attempt to get it's volume and see if it goes through and how:

obj1 = volume(100, 200, 400)
print(obj1.volume)
print(obj1.goes_through(obj1.x, obj1.y, obj1.z, 200, 350))

But I get this error instead:

[Previous line repeated 993 more times] RecursionError: maximum recursion depth exceeded

Any help is highly appreciated.


Solution

  • The problem is that your getters and setters are calling themselves. When you do self.x = x in your constructor, this calls your x setter. Then in your x setter, you also do self.x = x. This calls your x setter again. That again calls your x setter, and so on and so on until you run out of space on the stack and Python raises a RecursionError.

    You can get rid of all your setters and getters, and your code will work just fine.

    class coordinates(object):
        def __init__(self, x, y, z):
            self.x = x
            self.y = y
            self.z = z
    

    Alternatively, you could use different attribute names to store the data in your getters and setters, so that they don't call themselves.

    class coordinates(object):
        def __init__(self, x, y, z):
            self._x = x
            self._y = y
            self._z = z
    
        @property
        def x(self):
            return self._x
    
        @x.setter
        def x(self, x):
            self._x = x
    
        @property
        def y(self):
            return self._y
    
        @y.setter
        def y(self, y):
            self._y = y
    
        @property
        def z(self):
            return self._z
    
        @z.setter
        def z(self, z):
            self._z = z
    

    However, if you have no special reason to do something like this, it is simpler to not use getters and setters in the first place.