user1951363
user1951363

Reputation: 13

Variable declared in __init__ seems to be shared between class instances?

I wrote this piece of code and I can't figure out what I exactly did wrong. I create two instances of the 'Route' class, and somehow they share the value for the 'coords' list.

import random

class Route():
    def __init__(self):
        self.coords = []  
        self.distance = 0
    def Generate(self, cities):
        random.shuffle(cities)
        self.coords = cities

class Citymap():
    def __init__(self, nr):
        self.Nr_of_cities = nr
        self.cities = []
    def Generate_map(self):
        for i in range(0, self.Nr_of_cities):
            self.cities.append((random.randint(0, 750), random.randint(0, 750)))


city = Citymap(6)
city.Generate_map()

a = Route()
a.Generate(city.cities)

b = Route()
b.Generate(city.cities)

print a.coords
print b.coords

The output of a and b:

[(429, 713), (336, 611), (555, 465), (397, 227), (222, 412), (491, 322)]
[(429, 713), (336, 611), (555, 465), (397, 227), (222, 412), (491, 322)]

a and b should be different instances but somehow they end up sharing the 'coords' variable. Could someone help me out?

Upvotes: 1

Views: 81

Answers (3)

Colselaw
Colselaw

Reputation: 1079

It's subtle, but you're assigning the cities array and copying the address of the cities array around. so you're not passing city.cities to Generate, you're passing the actual array itself, then it gets assigned in the last line of the Generate function.

You can see this by doing:

print id(a.coords)
print id(b.coords)

I was able to get it to work as expected as follows:

import random
from copy import copy

class Route():
    def __init__(self):
        self.coords = []  
        self.distance = 0
    def Generate(self, cities):
        random.shuffle(cities)
        self.coords = cities

class Citymap():
    def __init__(self, nr):
        self.Nr_of_cities = nr
        self.cities = []
    def Generate_map(self):
        for i in range(0, self.Nr_of_cities):
            self.cities.append((random.randint(0, 750), random.randint(0, 750)))


city = Citymap(6)
city.Generate_map()

a = Route()
a.Generate(copy(city.cities))

b = Route()
b.Generate((city.cities))
print a.coords
print b.coords
print a
print b
print id(a.coords)
print id(b.coords)

Upvotes: 1

NPE
NPE

Reputation: 500457

The problem isn't the constructor, it's the Generate function. Change it to make a copy:

def Generate(self, cities):
    self.coords[:] = cities      # <<< note the [:]
    random.shuffle(self.coords)

Otherwise it not only mutates the list that's passed to it, but also keeps a reference to the list in self.coords, leading to the behaviour you describe.

Upvotes: 1

OneOfOne
OneOfOne

Reputation: 99274

You have to clone the city.cities list or it will just be shared between them :

a = Route()
a.Generate(city.cities[:])

b = Route()
b.Generate(city.cities[:])

Upvotes: 0

Related Questions