@property Decorator

class Box:
  def __init__(self, weight):
    self.__weight = weight
 
  def getWeight(self):
    return self.__weight
 
  def setWeight(self, weight):
    if weight >= 0:
      self.__weight = weight

###

box = Box(10)
 
box.setWeight(-5) 
print(box.getWeight()) #10
 
box.setWeight(5)
print(box.getWeight()) #5

Lo cual se puede simplificar de la siguiente forma:

class Box:
  def __init__(self, weight):
    self.__weight = weight
 
  def getWeight(self):
    return self.__weight
 
  def setWeight(self, weight):
    if weight >= 0:
      self.__weight = weight
 
  def delWeight(self):
    del self.__weight
 
  weight = property(getWeight, setWeight, delWeight, "Docstring for the 'weight' property")

###

box = Box(10)
 
print(box.weight) #this calls .getWeight()
 
box.weight = 5 #this called .setWeight()
 
del box.weight #this calls .delWeight()
 
box.weight = -5 #this called .setWeight() but box.__weight is unchanged

y aún más usando @property:

class Box:
 def __init__(self, weight):
   self.__weight = weight
 
 @property
 def weight(self):
   """Docstring for the 'weight' property"""
   return self.__weight
 
 
 @weight.setter
 def weight(self, weight):
   if weight >= 0:
     self.__weight = weight
 
 @weight.deleter
 def weight(self):
   del self.__weight

###

box = Box(10)
 
box.weight = 5
 
del box.weight

Link de referencia: https://www.codecademy.com/courses/learn-intermediate-python-3/articles/int-python-property-decorator