Почему итерация словаря Python, по-видимому, работает с копией?

Я смущен тем, как python перебирает этот словарь. Из документации python itervalues ​​возвращает итератор по значениям словаря.

dict = {"hello" : "wonderful", "today is" : "sunny", "more text" : "is always good"}

for x in dict.itervalues():
    x = x[2:]   

print dict

Это распечатывает исходный словарь без изменений. Почему это? Если я говорю, что значение в позиции x равно "blabla", почему оно не устанавливается?


person Justin    schedule 10.08.2011    source источник
comment
+1 за хороший вопрос. Это отбросило меня на секунду.   -  person Emil Ivanov    schedule 11.08.2011


Ответы (3)


Это не имеет ничего общего со строками или списками. Дьявол в том, как разворачивается for.

Делает

for x in d.iteritems():
    # loop body

более или менее эквивалентно выполнению

iter = d.itervalues()
while True:
    try:
        x = next(iter)
        # loop body
    except StopIteration:
        break

Итак, имея это в виду, нетрудно понять, что мы просто переназначаем x, который содержит результат вызова функции.

iter = d.itervalues()
while True:
    try:
        x = next(iter)

        x = 5 # There is nothing in this line about changing the values of d
    except StopIteration:
        break
person Emil Ivanov    schedule 10.08.2011
comment
Спасибо, это прояснило это для меня. Я бы хотел, чтобы документация по python более подробно объясняла такие вещи, как тонкости оператора for и различные методы. - person Justin; 11.08.2011

Единственное, что линия

x = x[2:]

делает создание фрагмента строки x[2:] и повторное связывание имени x, чтобы оно указывало на эту новую строку. Он не изменяет строку x, на которую указывал ранее. (Строки неизменяемы в Python, их нельзя изменить.)

Чтобы достичь того, чего вы на самом деле хотите, вам нужно сделать точку входа словаря на новый строковый объект, созданный срезом:

for k, v in my_dict.iteritems():
    my_dict[k] = v[2:] 
person Sven Marnach    schedule 10.08.2011
comment
Это не имеет ничего общего с неизменяемостью строк; если я заменю "hello":"wonderful" на "hello":[1,2], он будет работать так же. - person Mark Ransom; 10.08.2011
comment
@Mark: я также указал настоящую причину такого поведения - тот факт, что строки неизменяемы, является скорее примечанием. Однако это влияет на решение - если бы значения были списками, вы могли бы использовать for x in my_dict: del x[:2] для достижения желаемого поведения. - person Sven Marnach; 10.08.2011
comment
@Emil: я не понимаю твоего комментария. Это как-то связано с моим ответом? Или на мой комментарий? Это твой минус? - person Sven Marnach; 11.08.2011
comment
@Sven: Извините, после прочтения еще несколько раз это действительно правильно. - person Emil Ivanov; 11.08.2011

Как указывает Свен Марнах out, строки неизменяемы, и вы просто перепривязываете x к новой строке, созданной нотацией среза. Вы можете продемонстрировать, что x действительно указывает на один и тот же объект в словаре, используя id:

>>> obj = 'hello'

>>> id(obj)
<<< 4318531232

>>> d = {'key': obj}   

>>> [id(v) for v in d.values()]
<<< [4318531232]

>>> [id(v) for v in d.itervalues()]
<<< [4318531232]

>>> [(k, id(v)) for k, v in d.items()]
<<< [('key', 4318531232)]

>>> [(k, id(v)) for k, v in d.iteritems()]
<<< [('key', 4318531232)]

Вы можете использовать iteritems для повторения ключа и значения вместе, чтобы делать то, что вы хотите:

for k,v in dict.iteritems():
    dict[k] = v[2:]
person zeekay    schedule 10.08.2011