[python] имплементация слайсов для туплов
>>> t = tuple(range(100000Скушало очень многа памяти. Видать, копируется
>>> p = []
>>> for i in range(50000):
p.append(t[i:-i])
Ты имел в виду не "p+=t[i:-i]", а "p.append(t[i:-i])". Но да, копируются однако.
ок. спасибо!
Подпатчить сам класс tuple наверное нельзя, он небось на С целиком написан. А вот обёрточку можно сделать, и она даже наверное будет достаточно быстро работать, в присутствие Psyco.
Скушало очень многа памяти. Видать, копируетсяНеправильный тест.
как ты узнал что копировались данные, а не ссылки на них (указатели)?
Upd: у тебя данные (int) и указатели примерно одного размера.
Подпатчить сам класс tuple наверное нельзя, он небось на С целиком написанЭто верно для старого питона, версии типа 2.2
>>> class tup(tuple):
... def __init__(self, *args):
... print 'foo'
... return tuple.__init__(self, *args)
...
>>> tup([1,2])
foo
(1, 2)
Если бы получался объект "слайс", дающий прозрачный доступ к underlying immutable collection, то у него таких объектов получилось бы всего 50к штук, константного размера. А так у него получается 50к слайсов в среднем на 50к элементов каждый.
tuple.__getitem__ = mySlicer
TypeError: can't set attributes of built-in/extension type 'tuple'
Ты всегда можешь сделать свою обёртку!Psyco необязательно - можно просто написать на С класс
Подпатчить сам класс tuple наверное нельзя, он небось на С целиком написан. А вот обёрточку можно сделать, и она даже наверное будет достаточно быстро работать, в присутствие Psyco.
Есть tuple из 5 объектов, каждый объект размером 1мб.
Делаешь slice — первые два объекта tuple.
Объектов так и осталось 5 штук. Просто появилось 2 разных списка объектов — один это tuple из 5 указателей, второй это tuple из 2-х указателей на те же самые объекты.
Меняем 1 объект, он меняется в 2-х списках.
В коде:
fvv$ cat test.py
class Foo:
def __init__(self, i):
self.i = i
def __repr__(self):
return str(self.i)
a = tuple([Foo(x) for x in range(5)])
b = a[:2]
print a, b
a[0].i = 10
print a, b
fvv$ python test.py
(0, 1, 2, 3, 4) (0, 1)
(10, 1, 2, 3, 4) (10, 1)
Речь шла не об этом?
"Копируются ли объекты физически?" — "нет".
Элементы tuple (в твоём случае ссылки на объекты) копируются физически. А этого можно было бы избежать, представляя слайс как ссылку на исходный набор + диапазон индексов, благо immutable.
да, содержимое копируется. будь то ссылки или числа.
А о том, что если ты берёшь первый миллион элементов из тупла на два миллиона элементов, создаётся новый тупл на миллион элементов. Хотя достаточно было бы вернуть специальный объект слайс, который во всём ведёт себя как тупл, но вместо элементов хранит ссылку на родительский тупл и параметры слайса.
Хотя достаточно было бы вернуть специальный объект слайс, который во всём ведёт себя как тупл, но вместо элементов хранит ссылку на родительский тупл и параметры слайса.Это хорошая идея, которая во многих (возможно в большинстве) случаев позволит сэкономить память. Однако, в некоорых случаях она, наоборот, расход памяти повысит (см пример в конце). Таким образом, у нас есть два подхода: "обёртка" и "копия". Каждый из подходов имеет достоинства и недостатки. "Обёртку" можно эффективно реализовать на питоне, а вот "копию" на питоне эффективно реализовать нельзя. Подозреваю, что именно поэтому авторы питона реализовали на C именно "копию", считая, что те, кому надо "обёртку", сами легко её напишут.
А теперь пример, когда "обёртка" хуже "копии":
цикл 1000 раз:
t = <получить тупл на миллион элементов>
s = <вырезать из t интересующий нас слайс размером 1000 элементов>
<сохранить s для последующего использования>
конец цикла
при использовании "обёрток" после выполнения цикла в памяти будет в общей сложности миллиард элементов (так как внутри каждого слайса размером 1000 элементов будет жить тупл размером миллион элементов а при использовании "копий" в памяти будет всего миллион элементов.
При использованиии обёрток в памяти будет 1000000 элеиентов и 1000 обёрток. Без них - 2000000 элементов... В чём проблемъ?
Проблема в том, что тупл на миллион элементов на каждой итерации новый и миллон элементов в нём тоже свой.
тогда можно ещё аккуратнее реализовать обёртки
только пример, когда копия лучше обёртки можно ещё проще придумать: скажем, если тебе дали тупл на миллион объектов, а тебе оттуда нужнен подтупл из 10 элементов, то в случае копии, после того как 10 элементов скопировал, тот миллион уже не нужен и его можно почистить, а в случае обёртки, эти десять элементов будут тянуть за собой изначальный миллион.
другой вопрос, что обе ситуации, на мой взгляд встречаются достаточно часто, так что можно было бы и поддержку обёртки встроить в язык (в смысле, в стдлиб).
и я бы, например, сделал так что, слайс возращал бы обёртку, а для явного копирования, можно было бы эту обёртку передать в конструктор туплу:
>>> t = range(1000000) # type(t) == 'tuple'
>>> s = t[123456:234567] # type(s) == 'subtuple', хранит ссылку на t, чтобы того не убили
>>> t2 = tuple(s) # здесь всё физически копируется как и из любого другого итерабла
Там же довольно просто всё. Особенно если не ставить целью нахождение строгого минимума.
Оставить комментарий
psihodog
Кто-нть знает, если я беру слайс у тупла, физически данные копируются или нет?В основном интересует оригинальный интерпретатор CPython.