Python: Only allow attributes to be set that have a @property decorator

class MyClass():
   def __init__(self):
      self.attribute_1 = "foo"
      self.attribute_2 = "bar"
 
   @property
   def attribute_1(self):
     return self._attribute_1

   @attribute_1.setter
   def attribute_1(self,s):
     self._attribute_1 = s

   @property
   def attribute_2(self):
     return self._attribute_2

   @attribute_2.setter
   def attribute_2(self,s):
     self._attribute_2 = s

>>> ob = MyClass()
>>> ob.attribute_1 = 'fizz' #Ok
>>> ob.atribute_1 = 'buzz' #want to throw an exception because this has no setter or @property def

I would like my class to complain if we try and set an attribute that has not been decorated with property and a setter. I have tried using slots but can't get it working with the property decorator. 'attribute' in __slots__ conflicts with class variable

Any thoughts?

1 answer

  • answered 2020-08-12 22:58 Tadhg McDonald-Jensen

    __slots__ should contain all instance variables, in your case it is _attribute_1 and _attribute_2 (the ones with underscores used internally) so just do that:

    class MyClass():
       __slots__ = ["_attribute_1", "_attribute_2"]
       pass # rest of implementation
    

    note that if your property is just directly forwarding you might as well just put the public variables in the slots and only have properties for fields that need more validation or other logic. having slots is effectively a property really:

    >>> MyClass._attribute_1
    <member '_attribute_1' of 'MyClass' objects>