ТЗ на таблицу.
Создать двумерную прямоугольную матрицу-таблицу для хранения однотипных простых данных. Данные в таблице не редактируются, но могут дополняться путем добавления столбцов или строк. При любом добавлении таблица должны сохранять прямоугольную форму: все строки остаются одинаковой длины и все столбцы также.
Должны быть предусмотрены методы чтения строк и столбцов. При этом необходимо закрыть методы редактирования столбцов и строк.
Строки в таблицу добавляются часто. Их может быть до нескольких сотен тысяч. Столбцов в среднем от пяти до десяти, максимум - не более пятисот. Столбцы добавляются намного реже, чем строки. Но читаться будут в основном только столбцы. Более того, основная задача внешних объектов - читать столбцы.
Дополнение к следующей версии: предусмотреть удаление строк и столбцов, автоудаление старых строк, при достижении определенного лимита.
Анализ:
Так как столбцы будут читаться чаще всего, то выгоднее их поместить в более низкоуровневый контейнер, типа list или array.array. Второй контейнер даже предпочтительнее. Если строки хранить в подобных контейнерах, тогда упростится добавление строк, но усложнится чтение и анализ столбцов.
Для ограничения чтения можно использовать 3 метода: хранить данные в константных контейнерах типа tuple, копировать данные, передавать обёртку, закрывающую методы редактирования. Для строк будем использовать копирование, чтобы не передавать ссылку на всю таблицу, для столбцов - обёртки, так как большие столбцы часто копировать неэффективно.
Черновой код:
class ArrayCover():
def __init__(self, list_):
self.__list = list_
def __getitem__(self, index):
return self.__list[index]
def __str__(self):
return str(list(self.__list))
class RectMatrix:
def __init__(self, type_):
self.__matrix = []
self.__colLength = 0
self.__type = type_
def __repr__(self): # basic purpose of this function is testing
res = ''
for i in xrange(self.__colLength):
res += repr(self.get_row(i)) + '\n'
return res
def add_column(self, column):
if not len(column): return
if len(self.__matrix):
self.__matrix.append(column[:self.__colLength])
if len(self.__matrix[-1]) < self.__colLength:
self.__matrix[-1].extend(
[self.__matrix[-1][-1]]*(self.__colLength - len(self.__matrix[-1])))
else:
self.__matrix.append(column)
self.__colLength = len(column)
def add_row(self, row):
if not len(row): return
if len(self.__matrix):
for i, col in enumerate(self.__matrix):
if i < len(row):
col.append(row[i])
else:
col.append(0)
else:
import array
self.__matrix = [array.array(self.__type, [data]) for data in row]
self.__colLength += 1
def get_row(self, index = -1):
if index < self.__colLength and self.__colLength:
return [col[index] for col in self.__matrix]
def get_column(self, index):
if index < len(self.__matrix) and len(self.__matrix):
return ArrayCover(self.__matrix[index])
def get_column_length(self):
return self.__colLength
def get_row_length(self):
return len(self.__matrix)