Zepphit
Zepphit

Reputation: 61

When setting variable to object, set it to all nested objects within

I have the following code that works:

class fundamental_object():

    def __init__(self,x):
        self.x = x

class encapsulator_object():

    def __init__(self,x,obj_list):
        self._x = x
        self.obj_list = obj_list

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

    @x.setter
    def x(self,new_x):
        print('in setter!')
        self._x = new_x
        for obj in self.obj_list:
            obj.x = new_x

if __name__ == '__main__' :
    x = 10
    obj_1 = fundamental_object(x)
    obj_2 = fundamental_object(x)
    obj_list = [obj_1,obj_2]
    encapsulator = encapsulator_object(x,obj_list)

    encapsulator.x = 20
    print(encapsulator._x)
    print(obj_1.x) # all of these are also updated to 20.

As you can see, the idea is that, whenever I change the attribute "x" of the encapsulator object, I want all nested objects inside it (fundamental_objects) to also be updated with this new variable "x". However, from a user standpoint, this gets confusing really quickly, since, if I understand correctly, "x" is an integer for "fundamental_object", whereas "x" is a method for "encapsulator_object", and to actually access the integer in the encapsulator I would need to use "_x". Is there any easy/correct/pythonic way to make it so the following works :

    x = 10
    obj_1 = fundamental_object(x)
    obj_2 = fundamental_object(x)
    obj_list = [obj_1,obj_2]
    encapsulator = encapsulator_object(x,obj_list)

    encapsulator.x = 20
    print(encapsulator.x) # notice the underscore is now gone!  
    print(obj_1.x)        # this would be updated to 20 as well

I understand that it is possible to make it so "fundamental_objects" also have "_x" as the integer variable, which would somewhat reduce the confusion, but still, I'd like to completely get rid of the underscores if possible! (right now I get an infinite recursion). Thanks!

Upvotes: 0

Views: 355

Answers (1)

S.B
S.B

Reputation: 16536

Check this code. I only changed your getter method in your property. Now it is pointing to the self._x.

class fundamental_object():
    def __init__(self, x):
        self.x = x


class encapsulator_object():
    def __init__(self, x, obj_list):
        self._x = x
        self.obj_list = obj_list

    @property
    def x(self):
        return self._x   # -----> here

    @x.setter
    def x(self, new_x):
        print('in setter!')
        self._x = new_x
        for obj in self.obj_list:
            obj.x = new_x


if __name__ == '__main__':
    x = 10
    obj_1 = fundamental_object(x)
    obj_2 = fundamental_object(x)
    obj_list = [obj_1, obj_2]
    encapsulator = encapsulator_object(x, obj_list)

    encapsulator.x = 20
    print(encapsulator.x)  # notice the underscore is now gone!
    print(obj_1.x)  # this would be updated to 20 as well

As an alternative you can completely remove x or _x in encapsulator_object. Then in your getter you can find x within the self.obj_list :

class fundamental_object():
    def __init__(self, x):
        self.x = x


class encapsulator_object():
    def __init__(self, obj_list):
        self.obj_list = obj_list

    @property
    def x(self):
        return self.obj_list[0].x

    @x.setter
    def x(self, new_x):
        print('in setter!')
        for obj in self.obj_list:
            obj.x = new_x

Bear in mind that, in this example because we decided to pick first item in the list, all objects must have the same x value. There is no need to worry about it after you can the setter though. I mentioned it if you want to call the getter before setter.

Upvotes: 1

Related Questions