Как правильно реализовать членов экземпляра наследника абстрактного класса?
Есть абстрактный класс Foo
from abc import ABC
class Foo(ABC):
pass
Как сделать так, чтобы у экземпляров всех наследников этого класса был обязательно объявлен член self.foo?
Находил решения реализации абстрактных property класса, но это не то, что нужно, так как нужно, чтобы этот член был доступен и для чтения, и для записи.
Зачем
Есть базовый класс Descriptor
from abc import ABC
class Descriptor(ABC):
pass
Дескриптор подразумевает, что у него должны быть какие-то поля (например, self.fields = dict()). К примеру, дескриптор файла:
class FileDescriptor(Descriptor):
def __init__(self):
self.fields = dict(
name='name',
path=PathDescriptor(),
...
)
Далее этот дескриптор необходимо будет обогатить. Например,
def enrich(self, data):
self.fields.update(data)
И так же должна быть возможность читать поля этого дескриптора
file_desc = FileDescriptor()
file_desc.enrich(dict(name='new name'))
print(file_desc.fields['name'])
Необходимо, чтобы нельзя было инстанцировать наследников Descriptor (например, FileDescriptor) без объявленного в нём self.fields. Как это правильно реализовать?
Есть подозрения, что для этой задачи подойдут dataclasses, но ни разу с ними не работал и пока не представляю, как это применить и применимо ли это вообще.
Ответы (1 шт):
Для обновления содержимого словаря не обязательно, чтобы property было изменяемым
class C(ABC):
@property
@abstractmethod
def fields(self):
...
class D(C):
def __init__(self):
self._fields = {}
@property
def fields(self):
return self._fields
>>> x = D()
>>> x.fields
{}
>>> x.fields['key'] = 'value'
>>> x.fields.update({'key2': 'value2'})
>>> x.fields
{'key': 'value', 'key2': 'value2'}
Ну а даже если нужно позволять менять не только содержимое, но и саму ссылку, property и так тоже умеет
class C(ABC):
@property
@abstractmethod
def fields(self):
...
class D(C):
def __init__(self):
self._fields = {}
@property
def fields(self):
return self._fields
@fields.setter
def fields(self, newfields):
self._fields = newfields
>>> x = D()
>>> x.fields
{}
>>> x.fields = {'1': 2}
>>> x.fields
{'1': 2}