Назначить итераторы для фрагмента Python - PullRequest
0 голосов
/ 13 ноября 2018

Используются ли итераторы перед назначением на слайс в Python? Под «потребляется до назначения» я подразумеваю, что элементы создаются в памяти одновременно (помещаются в список или кортеж) до того, как произойдет назначение среза. Другой подход заключается в том, чтобы поместить элементы из итератора в срез один за другим, чтобы элементы не создавались в памяти одновременно.

Например, давайте рассмотрим этот код:

from itertools import islice
from heapq import merge

c = [0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5] + list(range(10))
lo, mid, hi = 0, 10, 20
c[lo:hi] = merge(islice(iter(c), lo, mid), islice(iter(c), mid, hi))

Слияние возвращает итератор, который выбирает наименьший элемент из двух итераторов, данных для слияния. Будут ли эти итераторы задействованы до того, как произойдет назначение слайса?

Ответы [ 2 ]

0 голосов
/ 13 ноября 2018

ОБНОВЛЕННЫЙ ОТВЕТ:

Да, данные итераций потребляются до перехода к slice ():

Для эмпирического доказательства простой пример с памятью ок. потребляющих:

1.) Пример кода с 10e6 элементами массива.

from itertools import islice
from heapq import merge

c = [0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5] + list(range(int(10e6)))
lo, mid, hi = 0, 10, 20

c[lo:hi] = merge(islice(iter(c), lo, mid), islice(iter(c), mid, hi))

Нет заметных затрат времени и памяти.

2.) Тот же код с 10e7 элементами массива.

c = [0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5] + list(range(int(10e7)))

означает 30% от общего потребления памяти той же конфигурации.

3.) Тот же код с 10e8 элементами массива.

Заканчивается в 100% + памяти, конечно.

Обратите внимание, что объем нарезки остался прежним , но память потребление значительно увеличилось.

0 голосов
/ 13 ноября 2018

Это зависит от реализации последовательности, которой назначается срез.Последовательность получает итератор напрямую, а сведения о потреблении итератора вплоть до последовательности.

Для списков текущая реализация CPython потребляет итератор заранее перед любым изменением списка:

v_as_SF = PySequence_Fast(v, "can only assign an iterable");

PySequence_Fast создаст список из любого аргумента, который еще не является списком или кортежем.

Существует также обработка самопредставления,потому что превращение ввода в список недостаточно для обеспечения безопасности при назначении списка самому себе:

/* Special case "a[i:j] = a" -- copy b first */
v = list_slice(b, 0, Py_SIZE(b));

Я не думаю, что какое-либо из этих действий списка задокументировано.

...