Search code examples
pythonpropertiesdecoratorpython-decorators

Print in getter of a property not working?


I am new to python, currently trying to learn properties.

class Car(object):
    def set_speed(self, speed):
        self._speed = speed
        print("set speed to {}".format(self.speed))


    def get_speed(self):
        return self._speed
        print("the speed is {}".format(self.speed))


    speed = property(fget = get_speed, fset=set_speed)

car1 = Car()
car1.speed = 170
x = car1.speed

The output I get is set speed to 170

That is all well and fine, and there is no surprise here since car1.speed was called. However, why was there never a "The speed is 170" printline? car1.speed was called in the same manner? Is there something I have not understood?


Solution

  • You used a return statement before the print() call. The function execution ends at that point, the print() is never reached:

    def get_speed(self):
        # return ends a function
        return self._speed
        # anything beyond this point is ignored
        print("the speed is {}".format(self.speed))
    

    Put the print() call before the return statement:

    def get_speed(self):
        print("the speed is {}".format(self._speed))
        return self._speed
    

    I corrected the print() function to show self._speed (with an underscore in the attribute name), otherwise you'd get into an infinite recursion (since self.speed would trigger the property again getter). You probably want to do the same in the set_speed() function, as that'll trigger the get_speed() getter too and you'll see the speed is <newspeed> printed before set speed to <newspeed> is printed each time you change the speed:

    class Car(object):
        def set_speed(self, speed):
            self._speed = speed
            print("set speed to {}".format(speed))
    
        def get_speed(self):
            print("the speed is {}".format(self._speed))
            return self._speed
    
        speed = property(fget = get_speed, fset=set_speed)
    

    Next, you can use the property object as a decorator; the resulting property instance has a setter() method that can then be re-used to decorate the setter too:

    class Car(object):
        @property
        def speed(self):
            print("the speed is {}".format(self._speed))
            return self._speed
    
        @speed.setter
        def speed(self, speed):
            self._speed = speed
            print("set speed to {}".format(speed))
    

    See How does the @property decorator work? as to how that works.