views:

81

answers:

2

Specifically, I want to create a backup of a list, then make some changes to that list, append all the changes to a third list, but then reset the first list with the backup before making further changes, etc, until I'm finished making changes and want to copy back all the content in the third list to the first one. Unfortunately, it seems that whenever I make changes to the first list in another function, the backup gets changed also. Using original = backup didn't work too well; nor did using

def setEqual(restore, backup):
    restore = []
    for number in backup:
        restore.append(number)

solve my problem; even though I successfully restored the list from the backup, the backup nevertheless changed whenever I changed the original list.

How would I go about solving this problem?

+8  A: 

You want copy.deepcopy() for this.

Ignacio Vazquez-Abrams
don't forget to 'import copy' to use this :)
Morlock
+5  A: 

The first thing to understand is why that setEqual method can't work: you need to know how identifiers work. (Reading that link should be very helpful.) For a quick rundown with probably too much terminology: in your function, the parameter restore is bound to an object, and you are merely re-binding that identifier with the = operator. Here are some examples of binding the identifier restore to things.

# Bind the identifier `restore` to the number object 1.
restore = 1
# Bind the identifier `restore` to the string object 'Some string.'
# The original object that `restore` was bound to is unaffected.
restore = 'Some string.'

So, in your function, when you say:

restore = []

You are actually binding restore to a new list object you're creating. Because Python has function-local scoping, restore in your example is binding the function-local identifier restore to the new list. This will not change anything you're passing in to setEqual as restore. For example,

test_variable = 1
setEqual(test_variable, [1, 2, 3, 4])
# Passes, because the identifier test_variable
# CAN'T be rebound within this scope from setEqual.
assert test_variable == 1 

Simplifying a bit, you can only bind identifiers in the currently executing scope -- you can never write a function like def set_foo_to_bar(foo, bar) that affects the scope outside of that function. As @Ignacio says, you can use something like a copy function to rebind the identifier in the current scope:

original = [1, 2, 3, 4]
backup = list(original) # Make a shallow copy of the original.
backup.remove(3)
assert original == [1, 2, 3, 4] # It's okay!
cdleary