0

我需要创建几个相互引用(通常是循环引用)的对象。通常,可能涉及多个对象,但这里有一个简单的案例,我只需要一对相互引用的汽车:

class Car:
  def __init__(self, position, speed):
    self.position = position
    self.speed = speed
  def set_reference(self, other_car):
    self.other_car = other_car
  # ...


def main():
  # ...
  car1 = Car(pos1, spd1)
  car2 = Car(pos2, spd2)
  car1.set_reference(car2)
  car2.set_reference(car1)

没有引用另一辆车的汽车不是有效对象。所以理想情况下,我想set_reference__init__方法内部执行;这将更安全(没有机会使用无效对象)和更清洁(所有初始化都将按__init__预期执行)。

是否有任何巧妙的解决方案可以实现这一目标?我不介意一次创建两辆汽车,但每辆汽车都是一个独立的实体,因此它需要本身就是一个实例。

我也知道循环引用对 GC 来说很麻烦。我会处理的。

用例:

每辆车都充当另一辆车的备用车。汽车实例是“智能的”,也就是说,它们可以做很多工作。如果汽车实例不知道它的备份,这很烦人,因为它会阻止汽车完成操作,而无需每次都来自外部的引用。

4

3 回答 3

2

我不认为有一个很好的方法可以将set_reference()呼叫转移到__init__(),因为另一辆车可能还不存在。我可能会做这样的事情。

class Car:
  def __init__(self, position, speed):
    self.position = position
    self.speed = speed
  def set_reference(self, other_car):
    self.other_car = other_car
  @classmethod
  def create_pair(cls, car1_args, car2_args):
    car1 = cls(*car1_args)
    car2 = cls(*car2_args)
    car1.set_reference(car2)
    car2.set_reference(car1)
    return car1, car2

def main():
  car1, car2 = Car.create_pair((pos1, spd1), (pos2, spd2))

以下是如何将相同的概念扩展为更大的循环引用结构:

class Car:
  # ...
  @classmethod
  def create_loop(cls, *args):
    cars = [cls(*car_args) for car_args in args]
    for i, car in enumerate(cars[:-1]):
        car.set_reference(cars[i+1])
    cars[-1].set_reference(cars[0])
    return cars

然后你可以这样称呼它(有任意数量的汽车):

car1, car2, car3 = Car.create_loop((pos1, spd1), (pos2, spd2), (pos3, spd3))

您应该像这样设置参考:

>>> car1.other_car is car2 and car2.other_car is car3 and car3.other_car is car1
True
于 2012-04-30T19:22:33.390 回答
0

我建议将汽车数据结构与引用汽车序列的数据结构分开。 other_car看起来并不像严格属于 的数据,car而是表示在一些可迭代的汽车序列中。因此,最简单且逻辑上最一致的解决方案是定义一辆汽车,然后将其放入一系列汽车中。

于 2012-04-30T19:32:09.630 回答
0

如果您真的不想使用工厂方法,那么唯一真正的选择是强制用户事后对其进行配置。(在评论中考虑您所说的可能需要依赖循环的内容):

class Car:
  def __init__(self, position, speed):
    self.position = position
    self.speed = speed

  @staticmethod
  def setup(*args):
    for car, next in zip(args, args[1:]):
      car.other_car = next
    args[-1].other_car = args[0]

def main():
  ...
  car1 = Car(pos1, spd1)
  car2 = Car(pos2, spd2)
  Car.setup(car1, car2)

另一种选择是拆分分组:

class CarGroup(list):
    def other_car(self, car):
        index = self.index(car)+1
        index = 0 if index >= len(self) else index
        return self[index]

class Car:
    def __init__(self, position, speed, group):
        self.position = position
        self.speed = speed
        self.group = group
        self.group.append(self)

    @property
    def other_car(self):
        return self.group.other_car(self)

def main():
    ...
    group = CarGroup()
    car1 = Car(pos1, spd1, group)
    car2 = Car(pos2, spd2, group)
于 2012-04-30T19:26:55.587 回答