2013-05-18 3 views
0

Я написал функцию SwapCities, которая может менять записи 3 и 4 в списке.Почему изменился мой первоначальный список?

Так что f.e. [0,1,2,3,4] должно стать [0,1,2,4,3]. Эта функция работает отлично, но, как ни странно, мой первоначальный список также изменяется, чего я не хочу.

Это мой код:

def SwapCities(solution): 
    n = 3##randint(0,NumberOfCities-1) 
    m = 4##randint(0,NumberOfCities-1) 
    result = solution 
    temp1 = solution[n] 
    temp2 = solution[m] 
    result[n] = temp2 
    result[m] = temp1 
    return result 

print "Start" 
IncumbentSolution = list(x for x in range(0,NumberOfCities)) 
print IncumbentSolution 

print "After swap" NewSolution = SwapCities(IncumbentSolution) 
print NewSolution 

print "Original solution" 
print IncumbentSolution 

я получаю следующий результат:

How many cities? 
8 Start [0, 1, 2, 3, 4, 5, 6, 7] 
After swap [0, 1, 2, 4, 3, 5, 6, 7] 
Original solution [0, 1, 2, 4, 3, 5, 6, 7] (why did this change?!) 

Как вы можете видеть мое оригинальное решение изменилось, которое он не должен делать.

У меня нет подсказки, почему это происходит. Даже когда я меняю код таким образом, чтобы изменения были применены к копии исходного списка, я получаю этот результат. Может кто-нибудь объяснить, что я делаю неправильно?

IncumbentSolution = list(x for x in range(0,NumberOfCities)) 
print "Start" 
print IncumbentSolution 

print "After swap" 
tmpsolution = IncumbentSolution 
NewSolution = SwapCities(tmpsolution) 
print NewSolution 

print "Original solution" 
print IncumbentSolution 
+0

О копировании списков: http://stackoverflow.com/a/184660/577423 – Howard

+3

Стоит отметить, что вам не нужно временные переменные, чтобы сделать своп в Python - 'решение [п], решение [м ] = решение [m], решение [n] '. Это более короткое, более читаемое и более эффективное. –

+0

Возможный дубликат: http://stackoverflow.com/questions/11993878/python-why-does-my-list-change-when-im-not-actually-changing-it?rq=1 – carlosdc

ответ

6

SwapCities является мутирует содержимое solution. С solution указывает на тот же список, что и IncumbentSolution, значения внутри IncumbentSolution также изменены.


Чтобы сохранить исходные значения в IncumbentSolution, сделать новую копию списка:

tmpsolution = list(IncumbentSolution) 

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

import copy 
tmpsolution = copy.deepcopy(IncumbentSolution) 
+1

Я всегда рекомендую использовать 'список (IncumbentSolution)'. Он выполняет ту же работу, но более читабельна. '[:]' обычно путают новые пользователи Python (см., сколько вопросов есть об этом на SO в одиночку), и хотя это не всегда является хорошей причиной не использовать что-то, это когда мы имеем гораздо лучшую замену под рукой. –

+0

@ Lattyware: Хорошая идея. Сложно использовать 'arr [:]' особенно при использовании 'NumPy', так как там он возвращает представление, а не копию. – unutbu

1

Это потому, что вы изменили список внутри функции.

Передавая список функции вы просто создали другую ссылку на тот же объект, solution и IncumbentSolution фактически указывают на тот же объект списка.

Вы должны передать мелкую копию функции, используя IncumbentSolution[:].

>>> def func(x): 
...  return id(x) 
... 
>>> lis = range(5) 
>>> id(lis),func(lis)  #both `x` and `lis` point to the same object 
(163001004, 163001004) 

>>> id(lis),func(lis[:]) #pass a shallow copy, `lis[:]` or `list(lis)` 
(163001004, 161089068) 
Смежные вопросы