Properties

Motivation

  • Pythonicity: attributes should be public

    • Python is a language of consenting adults

    • Private would be a double underscore (__) prefix ⟶ does not play well with inheritance

    class Person:
        'class with attributes left unprotected'
        def __init__(self, firstname, lastname):
            self.firstname = firstname
            self.lastname = lastname
    
  • Can add a property later if necessary

    person = Person('Joerg', 'Faschingbauer')
    person.lastname = 'Haubentaucher'    # <--- write access possible but unwanted
    

Readonly Attributes

  • @property

  • Built-in decorator (Decorators)

  • ⟶ read-only attribute

    class Person:
        def __init__(self, firstname, lastname):
            self._firstname = firstname
            self._lastname = lastname
    
        @property
        def firstname(self):
            return self._firstname
    
        @property
        def lastname(self):
            return self._lastname
    
  • Attributes are protected

    person = Person('Joerg', 'Faschingbauer')
    person.lastname = 'Haubentaucher'
    
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    Cell In[4], line 2
          1 person = Person('Joerg', 'Faschingbauer')
    ----> 2 person.lastname = 'Haubentaucher'
    
    AttributeError: property 'lastname' of 'Person' object has no setter
    

And Write Access?

  • @attrname.setter

  • Decorator around setter method attrname

    class Person:
        def __init__(self, firstname, lastname):
            self._firstname = firstname
            self._lastname = lastname
    
        @property
        def firstname(self):
            return self._firstname
    
        @property
        def lastname(self):
            return self._lastname
    
        @lastname.setter
        def lastname(self, n):
            if n == 'Haubentaucher':
                self._lastname = n
            else:
                raise AttributeError('no!')
    
  • Fine grained access control on attribute

    person = Person('Joerg', 'Faschingbauer')
    person.lastname = 'Haubentaucher'
    
    person.lastname = 'Meier'
    
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    Cell In[7], line 1
    ----> 1 person.lastname = 'Meier'
    
    Cell In[5], line 19, in Person.lastname(self, n)
         17     self._lastname = n
         18 else:
    ---> 19     raise AttributeError('no!')
    
    AttributeError: no!
    

Calculated Attributes

class Person:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

    @property
    def fullname(self):
        return f'{self.firstname} {self.lastname}'
person = Person('Joerg', 'Faschingbauer')
person.fullname
'Joerg Faschingbauer'