class DescState:                            # Wykorzystanie stanu deskryptora
    def __init__(self, value):
        self.value = value

    def __get__(self, instance, owner):    # Przy pobieraniu atrybutów
        print('pobranie DescState')
        return self.value * 10

    def __set__(self, instance, value):    # Przy przypisywaniu atrybutów
        print('ustawienie DescState')
        self.value = value

# Client class
class CalcAttrs:
    X = DescState(2)                       # Atrybut klasy deskryptora
    Y = 3                                  # Atrybut klasy
    def __init__(self):
        self.Z = 4                         # Atrybut instancji

obj = CalcAttrs()
print(obj.X, obj.Y, obj.Z)                 # X jest obliczane, pozostałe nie są
obj.X = 5                                  # Przypisanie X jest przechwytywane
CalcAttrs.Y = 6                            # Wartość przypisana ponownie atrybutowi Y w klasie
obj.Z = 7                                  # Wartość przypisana ponownie atrybutowi Z w instancji
print(obj.X, obj.Y, obj.Z)

obj2 = CalcAttrs()                         # Atrybut X wykorzystuje współdzielone dane, podobnie jak Y!
print(obj2.X, obj2.Y, obj2.Z)

