Search code examples
pythonpython-decorators

Python setter not executed when setting nested property


I have the following Python code to represent the velocity of an object.

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

class Physics(object):
  def __init__(self, velocity):
    self.velocity = velocity

  @property
  def velocity(self):
    return self._velocity

  @velocity.setter
  def velocity(self, velocity):
    self._velocity = velocity
    self._hi_res_velocity = Vector(velocity.x * 1000, velocity.y * 1000)

My intent is for velocity.x to set both _velocity.x and _hi_res_velocity.x, but the setter isn't run in this case. I get the following:

>>> myObject = Physics(Vector(10, 20))
>>> myObject.velocity.x = 30
>>> myObject._velocity.x, myObject._hi_res_velocity.x
(30, 10000)

I think the getter for velocity is run and then x is set on that returned value, but is it possible to implement the behavior I want using properties? I feel like I'll have to rewrite my logic to make this work.


Solution

  • When you do this:

    myObject.velocity.x = 30
    
    |_______________|
            |
            |___ this part already resolved the property
    

    The myObject.velocity is already returning a Velocity instance, and this happens first. Then the .x which follows is just a normal attribute access, since the Vector class doesn't define a descriptor for handling x.

    I'll suggest a different design, make either the "velocity" or the "hi_res_velocity" a getter-only, i.e. one of them is computed from the other whenever needed. This will resolve your issue, and also has the advantage that you don't have to store the same state twice.