Свойства только для чтения в ООП в Python
Давайте рассмотрим класс, в котором все свойства приватные:
class Test:
def __init__(self):
object.__setattr__(self, '__prop1', 1)
object.__setattr__(self, '__prop2', 2)
Теперь сделаем так, чтобы эти свойства во
внешнем мире были доступны только для чтения.
Ранее мы такое уже делали через декоратор
property: геттер без сеттера.
Другой способ - запретить запись в методе
__setattr__, а чтение оставить через
обычные имена prop1 и prop2.
Значения лежат в приватных полях, снаружи
их подменяет __getattr__:
class Test:
def __init__(self):
object.__setattr__(self, '__prop1', 1)
object.__setattr__(self, '__prop2', 2)
def __getattr__(self, name):
if name in ('prop1', 'prop2'):
key = f'_{type(self).__name__}__{name}'
return object.__getattribute__(self, key)
raise AttributeError(name)
def __setattr__(self, name, value):
raise AttributeError("can't set attribute " + name)
Воспользуемся им для чтения свойств:
test = Test()
print(test.prop1) # выведет 1
print(test.prop2) # выведет 2
Попытка записать что-то в свойство приведет к ошибке:
test = Test()
test.prop1 = 2 # выдаст ошибку
Это именно то, что нам нужно: свойство можно прочитывать, но нельзя записывать.
Попытка прочитать несуществующее свойство выдаст ошибку:
test = Test()
print(test.prop3) # выдаст ошибку
Обратите также внимание на следующий нюанс:
когда мы делали свойства только для чтения
через property, то для чтения
использовали метод-геттер под декоратором.
Здесь мы обращаемся к свойствам, будто они
публичные. Но записать в них не сможем -
__setattr__ запись отклоняет.
Пусть дан вот такой класс User, свойства
которого доступны только для чтения с помощью
геттеров:
class User:
def __init__(self, name, age):
self.__name = name
self.__age = age
def get_name(self):
return self.__name
def get_age(self):
return self.__age
Переделайте код этого класса так, чтобы вместо
геттеров чтение шло через имена name
и age, а запись снаружи запрещал
метод __setattr__.