Прошу прощения, только получилось завести интернет на ноут.
В общем, суть проблемы:
Есть лист-подобный класс, который на вход принимает секвенцию. Он может принимать как встроенный тип int, так и кастомный, назовем его Int, у которого есть property value.
При приеме элемента типа Int он вызывает его метод value и сохраняет в приватный list значение int.
А при вызове __getitem__ он должен отдавать уже новый объект Int со своими специфическими атрибутами (допустим,
my_IntList[0].name == f'{my_IntList.name}[0]'
).
Вот в первой редакции все выглядело так:
class IntList:
def __init__(self, name, seq):
self._name = name
self._seq_duck_type(seq)
self.__seq = self._make_seq(seq)
def _make_seq(self, seq):
for idx, item in enumerate(seq):
if isinstance(item, Int):
item = item.value
self.__seq.append(Int(name=f'{self._name}[{idx}]',
value=item))
def __getitem__(self, idx):
idx = self._idx_duck_type(idx)
return self.__seq[idx]
но оказалось, что это вообще ни разу не быстро, ибо
for item in seq:
self.__seq.append(item)
по времени выполнения отличается кардинльно от
for item in seq:
self.__seq.append(Int(item))
Пожтому по второму проходу был использован вариант сохранения только значений, и возврата их же.
Но последующей обработкой поступающих значений в духе (ну это уже утрированно):
def func(val, idx=None):
if idx is None:
return process(val.name, val.value)
if isinstance(val, IntList):
return process(f'{val.name}[{idx}]', val[idx])
короче, каша. Хотя по скорости обработки удоветворительно, т.к. объявление больших массивов - не редкость, а прогон по всем элементам - уже не такая.
Вот сейчас третий проход

выглядит все так:
class IntList(KspVar):
def __init__(self, name, ref_type=None, item_type=None,
size=None, seq=None):
super().__init__(name,
ref_type=ref_type)
if not isinstance(item_type, type):
raise TypeError('item_type has to be subclass of KspVar')
if not issubclass(item_type, KspVar):
raise TypeError(
'item_type has to be subclass of KspVar')
self._item_type = item_type
self.__name = name
if seq is not None:
self._seq = self._init_seq(seq)
else:
self._seq = list()
if size is not None:
if self._seq:
if len(self._seq) < size:
raise AttributeError(
'size has to be greater or equal length of seq')
self._size = size
self._init_size = size
else:
self._size = 0
self._init_size = None
self._cashed = [None] * self._size
def _init_seq(self, seq):
if not isinstance(seq, list):
raise TypeError('seq has to be instance of list')
for item in seq:
if not isinstance(item, self.ref_type):
raise TypeError(
'all items of seq have to be instances of' +
f'{self.ref_type}')
return seq
@property
def item_type(self):
return self._item_type
def extend(self, seq):
if not isinstance(seq, list):
raise TypeError('has to be list')
for val in seq:
self.append(val)
def __getitem__(self, idx):
idx = self._check_idx(idx)
self._check_cashed_item(idx)
return self._cashed[idx]
def __setitem__(self, idx, val):
idx = self._check_idx(idx)
self._seq[idx]
self._check_cashed_item(idx)
self._cashed[idx] <<= val
def _check_idx(self, idx):
if not isinstance(KspIntVar, int):
raise TypeError('has to be int or int KspIntVar')
if isinstance(idx, KspIntVar):
idx = idx.val
return idx
def _check_cashed_item(self, idx):
if self._cashed[idx] is None:
self._cashed[idx] = \
self._item_type(name=f'{self.__name}[{idx}]',
value=self._seq[idx])
на что я еще в перспективе могу напороться, и в плане архитектуры, и в плане производительности?