Что значит "потреблять" в Python? В итераторе?

Я работаю в Python уже несколько месяцев, и мне пришло в голову, что я часто пропускаю словарный запас, который ускользает от меня на первый взгляд, вместо этого пытаясь понять суть идеи. Теперь, оглядываясь назад, я все еще нахожусь в замешательстве, не веря в то, что означает термин " потреблять" Мой первоначальный интерес исходил из объяснений итераторов, которые говорили о значении потребляемого итератора. Однако, оглядываясь вокруг, это не кажется обычным в лексиконе Python. Либо это? Копаясь здесь, вы найдете в основном ссылки на веб-службы и одно или два обсуждения того, как скрыть тот или иной результат функции.

Полагаю, чтобы разбить мое невежество на несколько базовых пунктов:

  1. Делает ли "потребление" разные вещи в разных контекстах Pythonic?
  2. Что происходит с данными, когда они потребляются, например, в iter()?
  3. Когда переменная присваивается результату итератора - предположительно потребляемой части данных - она ​​больше не принадлежит итератору?
  4. Можете ли вы использовать более одного значения из объекта итератора за один вызов итератора?

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

РЕДАКТИРОВАТЬ: Еще одна вещь... делает повторное значение (при вызове с next()) остаться в памяти?

6 ответов

Решение

По поводу 2.

На самом деле мы должны различать два случая.

Помните, что написал Грег Хьюгилл:

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

Первый случай:

итератор вычисляет объект, который он должен произвести при стимуляции; то есть произведенный объект не существовал до вызова next(), Следовательно, если объекту присвоено имя, этот последний выживет; если нет, объект будет существовать без привязки к имени в пространстве имен в течение определенного времени, а затем он исчезнет в памяти, то есть занимаемые им биты будут использованы для другого объекта позже или раньше.

Второй случай

когда итератор возвращает ранее существующие объекты, принадлежащие списку, кортежу, словарю и т. д. В этом случае каждый объект создается next() уже была привязка с именем. Затем, если объекту присваивается новое имя, когда он "высовывается" из итератора, к объекту будут привязаны два имени. И если объекту не присвоено имя, он будет по-прежнему привязываться только к одному имени, что достаточно для поддержания объекта живым.

В общем:

Каждый раз, когда объект создается по вызову итератора, если ему не назначено имя, единственным результатом операции является "использование" итератора. Это способ сказать, что даже если после создания объекта нет постоянных последствий, оно произошло, что пропустило след внутри итератора.

Говорят о потреблении итератора, когда объекту присваивается имя, однако я не хочу путать.

Замечания:

Фактически, в случае объекта, уже существующего в списке, скажем, может быть, что у него нет имени. Но список содержит ссылку на каждый объект, который он "содержит"... На самом деле список не "содержит" объекты, а только ссылки на объекты... Что ж, это выходит за рамки того, что я хотел сказать.

,

По поводу 3

Вы не должны писать 3: "Когда переменная назначена..."

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

,

По поводу 4

Я не думаю, что можно получить два возврата от итератора только с одним вызовом next()

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

Когда вызывающая сторона запрашивает "следующий" элемент у итератора, итератор предоставляет следующий элемент, а затем изменяет свое собственное состояние, чтобы он мог создать следующий элемент после этого. Обычно это то, что вы ожидаете.

Если у меня есть генератор, который производит последовательность увеличивающихся простых чисел, при первом вызове я получу 2 взамен. В следующий раз я получу 3. Если я дам вам ссылку на этот генератор, вы назовете его (как вы думаете, первый раз) и получите 5. Нет никакого способа "перезагрузить" генератор, так что он снова начнет с 2, за исключением создания совершенно нового экземпляра генератора. В этой ситуации я мог бы сказать, что я уже съел первые два элемента, прежде чем дать вам генератор.

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

В случае итератора, итератор - это производитель, который проходит через итерируемый объект и "производит" каждое значение, по одному за раз, по порядку. "Потреблять" данные из итератора просто значит использовать их.

Итераторы - это просто объекты, которые поддерживают методы __iter__ а также next, Общий вариант использования итераторов - это циклическое их повторение, где каждый раз в цикле результат iterator.next() будет назначен на переменную.

Имея это в виду, призыв к iterator.next() можно назвать "потреблением значения", потому что в общем случае вызов next изменяет состояние итератора, и невозможно вернуться к этому предыдущему состоянию.

Однако ничто не мешает итератору многократно возвращать одно и то же значение или даже обеспечивает способ возврата к предыдущему состоянию. В этих случаях использование слова "потреблять" может быть не применимо.

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

Я могу ответить на ваше первое замечание: потреблять - это исчерпывать итеративное, это значит запускать итерируемое из следующих элементов.

Делает ли "потребление" разные вещи в разных контекстах Pythonic?

Нет, "потребление" всегда делает одно и то же.

Что происходит с данными, когда они потребляются, например, в iter()?

Это больше не доступно с того места, где вы его получили.

Когда переменная присваивается результату итератора - предположительно потребляемой части данных - она ​​больше не принадлежит итератору?

Правильный. Как только итератор создает данные, данные больше не принадлежат итератору.

Можете ли вы использовать более одного значения из объекта итератора за один вызов итератора?

Обычно нет. Тем не менее, вы можете написать собственный итератор, который выдает более одного значения за раз.

Другие вопросы по тегам