Как изменить элементы итераторов с помощью итераторов?Т.е. как получить итераторы записи в Python? - PullRequest
4 голосов
/ 22 июня 2011

Мне очень нравится синтаксис Python, но, поскольку я пришел из C ++, я ничего не понимаю об итераторах в Python. В C ++ существует 2 вида итераторов - постоянные и модифицирующие (неконстантные). В python кажется (для того, что я видел), что есть только первый вид, и если вы хотите изменить элементы, вы должны использовать индексацию, которая не кажется мне удобной и такой общей. Позвольте мне проиллюстрировать это простым примером:

ab = ["a", "b"]
for (index, lett) in enumerate(ab):
    print "Firstly, lett is ab[index]?", lett is ab[index]
    lett = str(index)
    print lett
    print ab[index]
    print "But after, lett is ab[index]?", lett is ab[index]

Так что я не смог изменить список с помощью итератора. Он просто делает ленивые копии (см. Википедия ), как я обнаружил с помощью оператора is, поэтому есть способ сказать, что я хочу, чтобы это был непосредственно модифицирующий итератор вместо использования аккуратного

for variable in iterable_object:

синтаксис

Ответы [ 4 ]

9 голосов
/ 22 июня 2011

Синтаксис

for x in iterable

не создает ленивых копий - он назначает точные объекты в списке на x один за другим.Если эти объекты являются изменяемыми, вы можете изменить их:

a = [[1, 2], [3, 4]]
for x in a:
    x.append(5)
print a

print

[[1, 2, 5], [3, 4, 5]]

В вашем примере используется список строк.Строки неизменны в Python, поэтому вы не можете их изменять.

3 голосов
/ 22 июня 2011
def iset(iterable):
    for i, x in enumerate(iterable):
        def setter(value):
            iterable[i] = value
        yield setter, x
a = range(10)
for set_x, x in iset(a):
    set_x(x * 2)
print a

отпечатки

[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
0 голосов
/ 18 февраля 2014

Аналогичный сценарий ...

>>> a = b = 0
>>> a = 42
>>> a, b
(42, 0)

>>> a = b = [0]
>>> a[0] = 42
>>> a, b
([42], [42])

Хотя python использует ссылки для внутреннего использования, и оба значения a и b указывают на один и тот же объект 0, говоря, что a = 42 заменяет a, а не вещь a ссылки.Список можно использовать в качестве обходного пути, но он ни в коем случае не элегантен.

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

Я думаю, что метод enumerate все еще правильный путь.

0 голосов
/ 18 февраля 2014

Проблема здесь на самом деле не в том, как итераторы работают в python, а в том, как присваивание работает на большинстве типов python.Когда спрашивающий пытается перезаписать значение lett, которое действительно является псевдонимом ab [index] и должно казаться, что оно работает логически, на самом деле это не то, что происходит, а lett (ссылка или указатель lett, а не значение, на которое он указываетto) переназначается, чтобы указывать на константу его нового значения, это сильно отличается от перезаписи байтов в той области памяти, на которую она указывает.Этот способ работы необходим для того, чтобы позволить пиктографической типизации утки работать, когда имя переменной со временем может указывать на разные типы с разными размерами.Пожалуйста, смотрите эту страницу для более подробного объяснения того, что здесь происходит: http://gestaltrevision.be/wiki/python/aliases

Наиболее близким, что мы могли бы достичь, является ручной тип 'mutable integer', который позволит изменять его базовое значение в отличие от интонов Python.Однако нет смысла проходить здесь это вручную, как уже объяснено в этом вопросе .Хотя вопрос совершенно другой, это одна и та же основная проблема, и решение в равной степени приемлемо.Однако, если вы делаете это, я бы сначала подумал, можете ли вы реструктурировать свой код, чтобы избежать этого, во-первых, так как это довольно опасный и подверженный случайностям способ работы.

Вот пример из anответьте на вопрос "increment int object" для полного объяснения того, как взломать это вместе, см. вопрос, связанный выше, обратите внимание, что этот пример включает только уменьшение, другие операторы должны бытьреализован так же:

import sys
class FakeInt(int):
    def __init__(self, *arg, **kwarg):
        self._decr = False
        int.__init__(self, *arg, **kwarg)
    def __neg__(self):
        if self._decr:
            upLocals = sys._getframe(1).f_locals
            keys, values = zip(*upLocals.items())
            i = list(values).index(self)
            result = FakeInt(self-1)
            upLocals[keys[i]]=result
            return result
        self._decr = not self._decr
        return self
...