# что делать, если хотим иметь доступ к свойству класса, но нужно защитить его от случайного переопределения?
# и вообще, хотим теперь влиять на постановку новых атрибутов объектам, как это делать?

class Point:
    WIDTH = 100

    def __setattr__(self, key, value):  # вызывается всякий раз, когда ставим атрибут экземпляру
        # не важно, как мы это делаем: через точку, через функцию setattr или через метод класса
        if key == "WIDTH":
            raise AttributeError("Попытка изменения приватного свойства")
        else:
            self.__dict__[key] = value  # меняем любое другое свойство через словарь локальных свойств __dict__
            print("Атрибут проставлен")  # прописываем обязательно, иначе ничего добавляться не будет

    def set_coords(self, x, y):
        self.a = x  # будет голосить и отсюда
        self.b = y  # и отсюда


pt = Point()
print(pt.WIDTH)  # взять можно без проблем

setattr(pt, 'y', 11)  # здесь срабатывает __setattr__

pt.set_coords(100, 1000)  # и здесь тоже срабатывает __setattr_
print(pt.__dict__)

Point.WIDTH = 5  # опа, а здесь не работает!
print(Point.WIDTH)  # заметьте, изменить напрямую в классе можно без проблем, как раз потому, что не для класса

pt.WIDTH = 100  # а вот создать одноимённое свойство для объекта уже нельзя
print(pt.WIDTH)
