class Person:
    def __init__(self, name):               # Dla [Person()]
        self._name = name                   # Wywołuje __setattr__!

    def __getattribute__(self, attr):                 # Dla [obiekt.dowolny]
        print('pobieranie: ' + attr)
        if attr == 'name':                             # Przechwycenie wszystkich nazw
            attr = '_name'                              # Odwzorowanie na nazwę wewnętrzną
       return object.__getattribute__(self, attr)     # Tutaj unikanie pętli


    def __setattr__(self, attr, value):     # Dla [obiekt.dowolny = wartość]
        print('ustawienie: ' + attr)
        if attr == 'name':
            attr = '_name'                  # Ustawienie nazw wewnętrznych
        self.__dict__[attr] = value         # Tutaj unikanie pętli

    def __delattr__(self, attr):            # Dla [del obiekt.dowolny]
        print('usunięcie: ' + attr)
        if attr == 'name':
            attr = '_name'                  # Tutaj także unikanie pętli
        del self.__dict__[attr]             # jednak jest to o wiele rzadsze

bob = Person('Robert Zielony')              # bob ma zarządzany atrybut
print(bob.name)                             # Wykonuje __getattr__
bob.name = 'Robert A. Zielony'              # Wykonuje __setattr__
print(bob.name)
del bob.name                                # Wykonuje __delattr__

print('-'*20)
anna = Person('Anna Czerwona')              # anna także dziedziczy właściwość
print(anna.name)
#print(Person.name.__doc__)                 # Tutaj brak odpowiednika
