Reputation: 31
So I was programming something in python that had to do with assigning a class variable to an instance variable, and then changing the instance variable inside the init method. I simplified the code a bit, when I run it the class variable gets changed as well:
class Map():
map = [1,2,3]
def __init__(self):
self.map = Map.map
for i in range(len(self.map)):
self.map[i] = self.map[i] * 2
print("self.map =", self.map)
print("Map.map =", Map.map)
new_map = Map()
When I run it, I get the following output:
self.map = [1, 4, 9]
Map.map = [1, 4, 9]
Basically I was wondering why Map.map gets changed even though I only changed self.map?
Upvotes: 1
Views: 230
Reputation: 308111
In Python, assignment is not copying! It just gives you another name to access the same object.
If the object is immutable, such as a number or string, you won't notice the difference. But when you do an assignment to a mutable object such as a list, any changes made to that object get reflected in all the other assigned names, since they're still the same object.
To make a copy of a list you can use slice notation (the slice does a copy) or you can use the copy
module.
Upvotes: 1
Reputation: 172209
As others have noted, it's because you are using a mutable class variable.
As you are using the same list for all instances, having a class variable is pointless.
class Map():
map = [1,2,3]
def __init__(self):
self.map = Map.map[:]
Is completely functionally equivalent with:
class Map():
def __init__(self):
self.map = [1,2,3]
Which is much easier to understand.
In general, mutable class variables is a bad idea, except for some very specific circumstances.
Upvotes: -1
Reputation: 14144
self.map
and Map.map
are both pointing to the same list. In Python parlance, self.map
and Map.map
are both names for the same list.
Check to see if id(self.map) == id(Map.map)
, and you'll find that to be True
.
To get the behavior you want, assign a copy of Map.map to self.map.
Use either list()
self.map = list(Map.map)
or the slice syntax
self.map = Map.map[:]
The builtin copy module can be used for this as well, especially if you have nested lists.
Upvotes: 0
Reputation: 229301
What you want is this:
self.map = Map.map[:]
The reason is that when you do self.map = Map.map
, self.map
is pointing to the same object as Map.map
. So when you mutate self.map
you are also mutating Map.map
because it's the same object. It's the same phenomenon as here:
>>> a = [1, 2, 3]
>>> b = a
>>> b[0] = 4
>>> a
[4, 2, 3]
>>> b is a
True
What you instead want to do is copy the object. You can copy lists by doing list(a)
or a[:]
:
>>> a = [1, 2, 3]
>>> b = a[:]
>>> b[0] = 4
>>> a
[1, 2, 3]
>>> b
[4, 2, 3]
>>> b is a
False
Upvotes: 5