0

Consider the following Python class. I want to set the attr property of class A internally, which method is the preferred way? I do not want to implement the property setter method because the user of the class should not be allowed to alter the attribute.

class A:
    ''' Library code '''
    def __init__(self):
        self._attr = None

    @property
    def attr(self):
        return self._attr

    # first approach
    def _set_attr(self, data):
        # Set the underlying private attribute
        self._attr = data

    # second approach
    def _set_attr2(self, data):
        # This calls __setattr__() of the base class
        setattr(self, '_attr', data)

    # third approach
    def _set_attr3(self, data):
        # Assignes data directly to the instance attribute
        self.__dict__['_attr'] = data

   def sets_attr(self):
        ''' does calculations and only calls the setter when
            result is fulfilling some requirements. '''


class B(A):
    ''' User code - extend on library code
        User can set any attribute name except the protected name  'attr'
    '''


marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
BramAppel
  • 1,346
  • 1
  • 9
  • 21
  • The first approach is clearly the more sensible of these three options; there is no need to use `setattr` or `__dict__` with a fixed attribute name. But you should use the `@attr.setter` decorator with it. – kaya3 Feb 11 '20 at 09:47
  • Does this answer your question? [How to set attributes using property decorators?](https://stackoverflow.com/questions/1684828/how-to-set-attributes-using-property-decorators) – kaya3 Feb 11 '20 at 09:49
  • *"I do not want to implement the property setter method because the user of the class should not be allowed to alter the attribute."* Then why are you writing a setter method in the first place? The *purpose* of a setter method is to allow the user to alter the attribute. – kaya3 Feb 11 '20 at 09:52
  • I just made the question more clear considering the suggested setter method. – BramAppel Feb 11 '20 at 09:52
  • [You might want to use two underscores, not just one](https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references) – MkWTF Feb 11 '20 at 10:03

1 Answers1

4

I wouldn't use any approach. Your use case is not clear, but if you do not want a setter available, and setting this attribute will only be done from some other internal module/class you are providing with no special action on set, there is not much point in any wrapper here. Just use

my_object._attr = value # Or if only within the class itself, then self._attr = value

wherever you intended to call the setter. A setter is an API for setting - if you do not want to provide an interface for setting, don't.

kabanus
  • 24,623
  • 6
  • 41
  • 74
  • Presumably because this code is only used inside the class, it would always be `self._attr` (unless you specifically want to set the attribute on a different instance). But this hits the nail on the head. – kaya3 Feb 11 '20 at 10:02
  • *And* if you ever need to intercept all these cases, you can use a `property` with `def _attr()` I don't think there is anything wrong with having an accessor as part of the private api that isn't exposed. – juanpa.arrivillaga Feb 11 '20 at 10:58
  • @juanpa.arrivillaga I agree, there is no "wrong" here. Just preferences. Since Python does not have a real concept of "private" (beyond name conventions) this is what I prefer assuming nothing special needs to be done on setting and the setting itself is only meant to be done by the original developer. Wrappers seem extraneous to me in this case. – kabanus Feb 11 '20 at 11:04