class CardHolder:
    acctlen = 8                                  # Dane klasy
    retireage = 62.5

    def __init__(self, acct, name, age, addr):
        self.acct = acct                         # Dane instancji
        self.name = name                         # Te także wywołują metodę __setattr__
        self.age  = age                          # Zmiana nazwy __acct nie jest konieczna: nazwa jest sprawdzana
        self.addr = addr                         # Atrybut addr nie jest zarządzany
                                                 # Atrybut remain nie ma danych
    def __getattribute__(self, name):
        superget = object.__getattribute__                 # Bez pętli — jeden poziom w górę
        match name:
            case 'acct':                                   # Dla wszystkich pobrań atrybutów
                return superget(self, 'acct')[:-3] + '***'
            case 'remain':
                return superget(self, 'retireage') - superget(self, 'age')
            case _:
                return superget(self, name)                # name, age, addr: przechowane

    def __setattr__(self, name, value):
        match name:
            case 'name':                                   # Dla wszystkich przypisań atrybutów
                value = value.lower().replace(' ', '_')    # Atrybut addr przechowany w sposób bezpośredni
            case 'age':
                if value < 0 or value > 150:
                    raise ValueError('niepoprawny wiek')
            case 'acct':
                value = value.replace('-', '')
                if len(value) != self.acctlen:
                    raise TypeError('niepoprawny numer konta')
            case 'remain':
                raise TypeError('nie można ustawić remain')
        self.__dict__[name] = value                         # Unikanie pętli, oryginalne nazwy

