Определение @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
объект не меняет это.