Python make list copy, not reference [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 8 years ago.
I have list of int's called board in python code. I wan't to know, if it was modified, so I have code
self.oldboard = list(self.board)
#here is board modified, if it is possible
if not self.oldboard == self.board:
#this should execute only when board was modified
But oldboard is always equals to board, when I modify board, it modifies oldboard. How to make oldboard just copy of board, not reference?

When copying lists by the slice method (analogous to what you're currently doing):
new_list_copy = old_list[:]
you'll only get a "shallow" copy of the contents. This isn't suitable for lists that contain lists ("nested lists").
If you're trying to copy a nested list, a Pythonic solution is to use deepcopy from the copy module:
import copy
new_list_copy = copy.deepcopy(old_list)

Integers are immutable. I would recommend you familiarize yourself with the notions of shallow and deep copy operations, which you can find in the Python Docs here . In your case you most likely need to use deepcopy, as I would guess that you have several nested lists.

Related

Why does the remove() Method also Removes from Copies and How to Work Around it? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 2 years ago.
I've been experiencing a quite strange error while using python.
I have a variable named graph, which is a list of lists and I'm modifying and a variable copy which
is supposed to "remember" the original value of graph.
However, when I apply the remove() method to graphthe value of copy also changes!
Here is a reproducible example:
graph = [[1,2],[2,3],[3,1]]
copy = graph
print("graph =" + str(graph))
print("copy =" + str(copy))
graph[0].remove(2)
print("graph =" + str(graph))
print("copy =" + str(copy))
Does anyone know how to deal with this issue?
You're not creating a copy, you should use copy library which creates a new object which is a copy of the old object, you have two option:
Shallo Copy: A shallow copy creates a new object which stores the reference of the original elements. So, a shallow copy doesn't create a copy of nested objects, instead it just copies the reference of nested objects.
Deep Copy: A deep copy creates a new object and recursively adds the copies of nested objects present in the original elements.
Example of Shallow Copy:
import copy
graph = [[1,2],[2,3],[3,1]]
copied_graph = copy.copy(graph)
Example of Deep Copy:
import copy
graph = [[1,2],[2,3],[3,1]]
copied_graph = copy.deepcopy(graph)
In this case, if you use Shallow Copy you can add another element to your graph list and it wont be changed in copied_graph, but if you change one of the lists inside the graph list (nested objects) it will change in copied_graph and if you also want to prevent this, you should use Deep Copy.

What is the difference between shallow copy and '=' in Python? [duplicate]

This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
Closed 3 years ago.
x = Object1
b = Object2
What is the difference between
import copy
x = b
x = copy.copy(b)
Assignment statements in Python do not copy objects, they create bindings between a target and an object
copy doc #python.org
Thus if you really want to have the same object twice without any bindings between you can use the copy package.

faster copying of an object (like deepcopy)?

I have a class in python3 that contains a few variables and represents a state.
During the program (simulation) I need to make a big amount of copies of this state so that I can change it and still have the previous information.
The problem is that deepcopy from the copy module is too slow. Would I be better of creating a method in that class to copy an object, which would create and return a new object and copy the values for each variable? Note: inside the object there is a 3D list as well.
Is there any other solution to this? The deepcopy is really too slow, it takes more than 99% of the execution time according to cProfile.
Edit: Would representing the 3D list and other lists as numpy arrays/matrix and copying them with numpy inside a custom copy function be the better way?
For people from the future having the same problem:
What I did was creating a method inside the class that would manually copy the information. I did not override deepcopy, maybe that would be cleaner, maybe not.
I tried with and without numpy for 2D and 3D lists, but appending 2 numpy arrays later in the code was much more time consuming than making a sum of 2 lists (which I did need to do for my specific program).
So I used:
my_list = list(map(list, my_list)) # for 2D list
my_list = [list(map(list, x)) for x in my_list] # for 3D list

Python : Modifying Lists in For Loops [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 6 years ago.
I am trying to create card game simulations to improve my programming skills a bit, and i am stuck with the following problem:
I have the cards in a big list, and i use the next function to pick a card and remove it from the deck.
cards= [........(big list of cards here in string format).......]
def Pickacard(x):
rand=random.randint(0,len(x)-1)
t=int(x[rand])
del(x[rand])
return t
When i use the following iteration, the deck isnt beeing renewed. Instead every time a card gets picked, the deck remains 1 item shorter, despite the fact that in every loop, i have set "test=cards" so that it sets the list back to the original.
for i in range(200):
test=cards
Pickacard(test)
print(test)
Deck had 208 cards, if the deck was renewed then (print test) would give me a list of 207 cards. Instead i get a list of 8 cards. I though this would only happen if ....test=cards.... was outside of the loop.
When calling test = cards you are not copying the list cards in test. In fact, what you are doing is merely copying the pointer test into cards. So they are pointing on the same list. This is why the list keeps shrinking and is never renewed.
If you want to renew it, you have several possibilities. You could created a copy of the list with the following:
Slice it with test = cards[:] (not the best way of doing that)
Create it with list(): test = list(copy)
Explicit copy : test = copy.copy(cards) (must import the module copy first)
Else, you can save the card you deleted and reinsert it at the end of the loop. This avoids copying the list at each iteration. Though it's not crucial in your case, it's a good practice to think a bit about performances by avoiding unnecessary computing:
def Pickacard(x):
rand=random.randint(0,len(x)-1)
card = x[rand]
del(x[rand])
return card
for i in range(200):
card = Pickacard(cards)
print(cards)
cards.append(card)
You're copying the reference, not the list data. Try the following options.
import copy
test = copy.copy(cards)
OR
test = list(cards)
Also, read about Deep and Shallow Copy
In Python, variable is just an alias of an object. so in your program, test and cards are two alias of the same object. So when you delete an item in cards, test changes too.
If you want test to be another object, you can use
test = cards[:]
This will build a new List that contains all the item of cards.
You can see more about how to copy a List here
How to clone or copy a list in Python?

How to save a "self" variable in python? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 7 years ago.
In python, inside a class, it appears that when I save a "self" variable into another one, if I edit the new variable, the "self" is also edited:
undropped_lines = self.flagged_lines
print self.flagged_lines
del undropped_lines[0]
print self.flagged_lines
How should one avoid this trait in the code?
This is because lists are mutable and when you say undropped_lines = self.flagged_lines you are just pointing a new name at the same instance.
If you want a copy use undropped_lines = self.flagged_lines[:]
This is because undropped_lines and self.flagged_lines are pointing to the same data. Think of it as two different "names" pointing to the same entity.
You can get around this by creating a shallow copy of the list when assigning to undropped_lines. Something like:
undropped_lines = list( self.flagged_lines )

Categories

Resources