Python object referencing: 如何创建包含不同列表的列表

51 阅读3分钟

我的目标是创建一个包含多个列表的列表,其中每个列表都代表一个游览路线。然而,我遇到一个问题,在代码循环结束后,列表 tours 并不是一个包含多个不同、随机排列的游览路线的列表,而是包含了最后添加到列表中的游览路线。我想这与 Python 的对象引用有关,但我不知道该如何修改代码。我已经尝试使用 del tour,但没有效果。

huake_00066_.jpg 代码如下:

def initialisePopulation(self, cities):
    tours = []

    for i in xrange(0, PopulationSize):
        tour = Tour(cities)
        shuffle(tour.tour)
        tours.append(tour)
        print str(tour.tour[0].id) + "," + str(tour.tour[1].id) + "," + str(tour.tour[2].id) + "," + str(tour.tour[3].id) + "," + str(tour.tour[4].id)
        del(tour)
    print "-"
    for j in xrange(0, PopulationSize):
        print str(tours[j].tour[0].id) + "," + str(tours[j].tour[1].id) + "," + str(tours[j].tour[2].id) + "," + str(tours[j].tour[3].id) + "," + str(tours[j].tour[4].id)

当我打印每个游览路线时,一切都很正常。但是,当我打印 tours 的内容时,每个项目都是相同的。

输出如下:

2,3,1,5,4
2,4,3,1,5
2,3,4,1,5
4,3,1,5,2
3,4,1,5,2
-
3,4,1,5,2
3,4,1,5,2
3,4,1,5,2
3,4,1,5,2
3,4,1,5,2

Tour 类:

class Tour(object):
    '''
    classdocs
    '''

    def __init__(self, cityList):
        self.tour = cityList
        self.size = len(cityList)
        self.fitness = self.getFitness(self.tour)

    def getFitness(self, tour):
        fitness = sum([self.euclideanDistance(tour[i], tour[i+1]) for i in xrange(0, self.size-1)])
        return fitness

    def euclideanDistance(self, p, q):
        distance = sqrt((p.x - q.x)**2 + (p.y - q.y)**2)
        return  distance

2. 解决方案

答案 1:

有两种可能性导致了这个问题,但从你没有展示的代码中无法确定。

第一种可能性: 你将 tour 存储为 Tours 中的类属性而不是实例属性,因此它们共享相同的属性:

class Tour(object):
    tour = something

第二种可能性: 你将城市列表复制到 tour 实例属性中,因此它们具有不同的属性,但所有属性都引用同一个列表值:

class Tour(object):
    def __init__(self, cities):
        self.tour = cities

从你更新的问题来看,是第二种情况。

从根本上说,这与常见问题解答中的多维列表问题相同,只是这里不是直接有一个列表的列表,而是有一个包含列表的对象的列表。

无论哪种情况,你想让 Tour 中的每个对象有独立的列表,以便可以使用 shuffle 等函数对它们进行单独修改,对吧?那么你需要显式地复制列表。例如:

class Tour(object):
    def __init__(self, cities):
        self.tour = cities[:]

但是,我可能会对这段代码进行不同的编写。首先,创建一个不会执行就地修改的 shuffled 方法,而是返回一个新列表:

def shuffled(iterable):
    result = list(iterable)
    shuffle(result)
    return result

然后,你可以用这个方法替换整个第一个循环:

tours = [Tour(shuffled(cities)) for _ in xrange(PopulationSize)]

同时,你可以将第二个循环替换为:

for tour in tours:
    print ','.join(city.id for city in tour)

for tour in tours 这部分解释了 for 循环教程。第二行使用解析和 join 方法,可以避免重复五次。