Класс с атрибутами только для чтения - PullRequest
0 голосов
/ 11 июня 2019

Я хочу создать класс с атрибутами, которые могут быть __setattr__ -ed его методами внутри страны, поэтому попытка, подобная self.attr = value, вызовет AttributeError. Это то, что у меня есть:

class MyClass():
    def __init__(self, a, b, c):
        self.a, self.b, self.c = a, b, c

    def __repr__(self):
        return '%r class with a=%s, b=%s, c=%s' % (self, self.a, self.b, self.c)

    def __setattr__(self,attr,value):
        raise AttributeError('%r is read-only' % self)

    def setattr_(self,attr,value):
        self.attr = value


>>> obj = MyClass(1,2,3)
>>> obj.setattr_(a,4) # obj.a = 4
AttributeError: 'obj' is read-only # __setattr__ method also applies internally

Ответы [ 3 ]

1 голос
/ 11 июня 2019

Это вариант использования для свойств. Свойства без установщика доступны только для чтения. В дальнейшем a и b доступны только для чтения, а c - нет.

class MyClass:
    def __init__(self, a, b, c):
        self._a = a
        self.b = b
        self._c = c

    # a is a read-only property
    @property
    def a(self):
        return self._a

    # b is an ordinary attribute

    # c is a property you can set
    @property
    def c(self):
        return self._c

    @c.setter
    def c(self, value):
        self._c = value

Поскольку вы определили только геттеры для a, попытки изменить его значение не удастся. Попытки изменить b будут успешными, как и ожидалось. Попытки изменить c увенчаются успехом как если бы это был обычный атрибут.

>>> obj = MyClass(1,2,3)
>>> obj.a = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>> obj.b = 5
>>> obj.c = 6
>>> obj.c
6
0 голосов
/ 11 июня 2019

Пожалуйста, используйте свойства.

В любом случае, хорошо разбираться во внутренностях, вот рабочий код, основанный на вашем вопросе. Просто чтобы поиграть.

Как только вы переопределите __setattr__ для сбоя, невозможно установить атрибут в этом классе. Но в родительском классе еще есть рабочий __setattr__.

class MyClass():
    def __init__(self, a, b, c): 
        self.setattr_('a', a)
        self.setattr_('b', b)
        self.setattr_('c', c)

    def __setattr__(self,attr,value):
        raise AttributeError('%r is read-only' % self)

    def setattr_(self,attr,value):
        super().__setattr__(attr, value)

obj = MyClass(1,2,3)
obj.setattr_('a',4)  # note that a is a name (string)
0 голосов
/ 11 июня 2019

Вы можете использовать свойства в Python для задач этого типа.Сначала вы делаете свой атрибут «приватным», добавляя два подчеркивания, затем создаете метод получения с помощью декоратора @property:

class MyClass:
    def __init__(self, a, b, c):
        self.__a, self.__b, self.__c = a, b, c

    @property
    def a(self):
        return self.__a

    @property
    def b(self):
        return self.__b

    @property
    def c(self):
        return self.__c

Теперь вы можете использовать свой класс следующим образом:

>>> my_object = MyClass('foo', 'bar', 'bar')
>>> print(my_object.b)
bar
>>> my_object.b = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Примечание

Я написал 'private', потому что вы все равно можете получить к нему доступ, если действительно хотите:

>>> my_object._MyClass__b = 42
>>> print(my_object.b)
42

Это связано с Zen of Python : "Мы все здесь взрослые по обоюдному согласию".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...