2010-08-14 5 views
2
tokens_raw = {"foo": "bar"} 
tokens_raw_old = { } 
while not tokens_raw == tokens_raw_old: 
    tokens_raw_old = tokens_raw 
    # while loop that modifies tokens_raw goes here; 
    # tokens_raw_old is never referenced 
    print tokens_raw_old == tokens_raw 

Это приводит к истине после первого раза по какой-либо причине. tokens_raw_old имеет те же данные, что и tokens_raw, даже после того, как был изменен только tokens_raw. Я где-то ошибся, или проблема лежит во втором цикле (который, опять же, никогда не ссылается на tokens_raw_old)? Если нет очевидных ошибок, я отправлю больше кода.Почему меняется эта переменная?

ответ

7

tokens_raw_old = tokens_raw означает: сделать новую ссылку под названием token_raw_old к же объекта, к которому относится имя tokens_raw в это время. Это такой же объект, не копия объекта! Таким образом, изменения в этом и единственном объекте, выполненном через одну из ссылок, очевидно, также влияют на тот же самый объект, когда он рассматривается через другую ссылку.

Если вы хотите получить копию, попросите копию! Например, поскольку tokens_raw является ДИКТ с неизменяемыми значениями (и ключи, но это часто в dicts):

tokens_raw_old = tokens_raw.copy() 

будет достаточно. Одинаково (только вопрос стиля), так будет

tokens_raw_old = dict(tokens_raw) 

(сделать копию с помощью «вызова типа как конструктор копирования», понятие, которое обращается к программистам C++ - из которых я один, так что я действительно нравится эта форма ;-).

Если вам нужно покрыть для общего случая (tokens_raw существа из многих возможных различных типов или значений в нем быть, может быть изменен):

import copy 

tokens_raw_old = copy.deepcopy(tokens_raw) 

Это может быть довольно медленным, но, «когда вам нужен это вам нужно »- делает копию глубиной, т. е. копирует контейнер, а также все содержащиеся в нем объекты (рекурсивно, если контейнер содержит другие контейнеры - скажем, что три раза быстро...;-).

Не каждый объект может быть скопирован (глубоко или неглубоко) - например, объект открытого файла не может быть скопирован (вам нужны другие подходы, если у вас когда-либо были такие странные, передовые потребности). Но для dict с строками в качестве ключей и ценностей простые подходы, о которых я упомянул в начале этого ответа, будут достаточными и будут довольно быстрыми ;-).

+0

Я действительно ошибся в коде, который я вставил; tokens_raw - это список, а не dict, поэтому .copy() не является допустимым методом. Тем не менее, ответ по-прежнему имеет смысл, и я обнаружил, что использование 'tokens_raw_old = tokens_raw [:]' имеет тот же эффект, что и вы предложили. Спасибо за помощь. :) – Fraxtil

+1

@Fraxtil, конечно, но я лично ненавижу вечно популярный 'somelist [:]' idiom - 'list (somelist)' просто ** так ** намного читаем как способ мелкой копии списка (или, если на то пошло, составить версию списка любой входной последовательности). Ах, ну, дело в стиле, я думаю! -) –

Смежные вопросы