Сохранение памяти Py3k, возвращая итераторы, а не списки

Многие методы, используемые для возврата списков в Python 2.x, теперь возвращают итераторы в Py3k

Являются ли итераторы генераторными выражениями? Ленькая оценка?

Таким образом, при этом объем памяти python памяти резко сократится. Не правда ли?

Как насчет программ, преобразованных из 2to3, с помощью встроенного script?

Является ли встроенный инструмент явным образом преобразовывать все возвращенные итераторы в списки для совместимости? Если это так, то преимущество Py3k в работе с памятью на нижней части памяти явно не проявляется в преобразованных программах. Это?

Ответ 1

Многие из них не являются точно итераторами, а специальными объектами представления. Например, range() теперь возвращает нечто похожее на старый объект xrange - он все равно может быть проиндексирован, но лениво строит целые числа по мере необходимости.

Аналогично dict.keys() предоставляет объект dict_keys, реализующий представление на dict, вместо создания нового списка с копией ключей.

Как это влияет на следы памяти, вероятно, зависит от программы. Разумеется, здесь больше внимания уделяется использованию итераторов, если вам действительно не нужны списки, тогда как использование списков обычно было стандартным случаем в python2. Это приведет к тому, что средняя программа, вероятно, будет более эффективной с точки зрения памяти. Случаи, где есть действительно большие сбережения, вероятно, уже будут реализованы как итераторы в программах python2, так как действительно большое использование памяти будет выделяться и, скорее всего, уже будет рассмотрено. (например, файловый итератор уже намного эффективнее памяти, чем более старый метод file.readlines())

Преобразование выполняется с помощью инструмента 2to3 и, как правило, преобразует такие объекты, как range(), в итераторы, где он может безопасно определять реальный список, не нужен, поэтому код вроде:

for x in range(10): print x

переключится на новый объект range(), больше не будет создавать список, и поэтому получит уменьшенную выгоду памяти, но код вроде:

x = range(20)

будет преобразован как:

x = list(range(20))

поскольку конвертер не может знать, ожидает ли код реального объекта списка в x.

Ответ 2

Являются ли итераторы генераторными выражениями? Ленькая оценка?

Итератор - это просто объект со следующим методом. То, что документация означает большую часть времени, когда говорят, что функция возвращает итератор, заключается в том, что его результат лениво загружен.

Таким образом, при этом объем памяти python памяти резко сократится. Не правда ли?

Это зависит. Я бы предположил, что средняя программа не заметила бы огромной разницы. Преимущества производительности итераторов над списками действительно значительны, если у вас большой набор данных. Возможно, вы захотите увидеть этот вопрос.

Ответ 3

Одно из самых больших преимуществ итераторов по спискам - это не память, это фактически время вычисления. Например, в Python 2:

for i in range(1000000):  # spend a bunch of time making a big list
    if i == 0:
        break  # Building the list was a waste since we only looped once

Теперь возьмите, например:

for i in xrange(1000000):  # starts loop almost immediately
    if i == 0:
        break  # we did't waste time even if we break early

Хотя пример надуман, вариант использования не таков: петли часто выходят из середины. Создание всего списка, чтобы использовать его часть, является пустой тратой, если вы не собираетесь использовать ее более одного раза. Если это так, вы можете явно создать список: r = list(range(100)). Вот почему итераторы по умолчанию больше в Python 3; вы не из ничего, так как вы можете явно создавать списки (или другие контейнеры), когда вам нужно. Но вы не вынуждены, когда все, что вы планируете делать, - это повторить итерацию один раз (что я бы сказал, это гораздо более распространенный случай).