Определение @property

У меня есть проблема в определении геттера с помощью @property в конкретном классе. Вот код Python:

from abc import ABCMeta, abstractproperty

class abstract(object):
    __metaclass__ = ABCMeta

    def __init__(self, value1):
        self.v1 = value1

    @abstractproperty
    def v1(self):
        pass

class concrete(abstract):
    def __init__(self, value1):
        super(concrete, self).__init__(value1)

    @property
    def v1(self):
        return self.v1

Затем проверьте код и получите эту ошибку:

test_concrete = concrete("test1")
test_concrete.v1

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-190-eb896d7ec1c9> in <module>()
----> 1 test_concrete = concrete("test1")
      2 test_concrete.v1

<ipython-input-189-bf15021022d3> in __init__(self, value1)
     11 class concrete(abstract):
     12     def __init__(self, value1):
---> 13         super(concrete, self).__init__(value1)
     14 
     15     @property

<ipython-input-189-bf15021022d3> in __init__(self, value1)
      3 
      4     def __init__(self, value1):
----> 5         self.v1 = value1
      6 
      7     @abstractproperty

AttributeError: can't set attribute

В основном я намерен установить v1 как атрибут только для чтения.

Я привык использовать одно и то же имя для атрибута и его функции получения, но кажется, что я не могу сделать это, если класс унаследован от абстрактного класса.

Я нашел обходной путь, используя другое имя для функции получения v1 как get_v1:

class abstract(object):
    __metaclass__ = ABCMeta

    def __init__(self, value1):
        self.v1 = value1

    @abstractproperty
    def get_v1(self):
        pass

class concrete(abstract):
    def __init__(self, value1):
        super(concrete, self).__init__(value1)

    @property
    def get_v1(self):
        return self.v1

Есть ли лучший обходной путь для этой проблемы?

1 ответ

Решение

Ваша проблема не имеет ничего общего с абстрактными классами. Это проблема пространства имен; Атрибуты объекта и экземпляра свойства занимают одно и то же пространство имен, и атрибут экземпляра, и свойство не могут использовать одно и то же имя.

Вы пытаетесь получить доступ к собственности с помощью self.v1 = ... а также v1 магически не является атрибутом экземпляра только потому, что вы обращаетесь к нему из метода экземпляра, который всегда будет объектом свойства.

В том же духе, ваш метод получения свойства будет вызывать бесконечный цикл:

@property
def v1(self):
    return self.v1

так как self.v1 является объектом свойства, а не атрибутом экземпляра.

Используйте другое имя для фактического хранилища:

def __init__(self, value1):
    self._v1 = value1

@property
def v1(self):
    return self._v1

Обратите внимание, что вы не можете иметь по-настоящему приватные атрибуты в Python (как вы можете в C# или Java); Подчеркивание имен - это всего лишь соглашение, и определенный кодер всегда может напрямую получить доступ к вашему состоянию экземпляра. property объект не меняет это.

Другие вопросы по тегам