我在这个跟踪派系联盟的程序中哪里搞砸了?

Where did I mess up in this program for tracking faction alliances?

我有一个模拟王国和其他团体的程序(在我的代码中称为 'factions')。

class Faction:
    def __init__(self, name, allies=[]):
        self.name = name
        self.allies = allies

    def is_ally_of(self, other_faction):
        if self in other_faction.allies:
            return True
        else:
            return False

    def become_ally(self, other_faction, both_ally=True):
        """ If both_ally is false, this does *not* also 
            add self to other_faction's ally list """
        if self.is_ally_of(other_faction):
            print("They're already allies!")
        else:
            self.allies.append(other_faction)
            if both_ally == True:
                other_faction.become_ally(self, False)

RezlaGovt = Faction("Kingdom of Rezla")
AzosGovt = Faction("Azos Ascendancy")

我希望能够调用派系 become_ally() 方法来将派系添加到盟友列表中,如下所示:

RezlaGovt.become_ally(AzosGovt) # Now AzosGovt should be in RezlaGovt.allies,
                                # and RezlaGovt in AzosGovt.allies

实际情况是这样的:

RezlaGovt.become_ally(AzosGovt)
# prints "They're already allies!"
# now AzosGovt is in the allies list of both AzosGovt and RezlaGovt, 
# but RezlaGovt isn't in any allies list at all.

每当我尝试调用 become_ally() 时,代码应该检查以确保它们不是盟友。这是不起作用的部分。每次我调用 become_ally() 时,它都会打印 "They're already allies!",不管它们是否确实如此。

我也试过用if self in other_faction.allies:,但还是有同样的问题。

我强烈怀疑问题出在我使用 self 上,但我不知道要 Google 了解更多信息。

You can't use mutable arguments as the default argument to a function.

def __init__(self, name, allies=[]):

使用默认时,每次都是相同list,所以它们有相同的allies;改变一个会改变另一个,因为它们实际上是同一件事。

更改为:

def __init__(self, name, allies=None):
   if allies is None:
       allies = []

或者,无条件地复制 allies 参数(这样你就不用担心在 class 之外存在对它的引用并在 class 下发生变异):

def __init__(self, name, allies=[]):
    self.allies = list(allies)  # Which also guarantees a tuple argument becomes list
                                # and non-iterable args are rejected

更改此功能。

def is_ally_of(self, other_faction):
        if other_faction in self.allies:
            return True
        else:
            return False

检查您自己的数据,而不是传入对象的数据。

还有

def __init__(self, name, allies=[]):

是一个等待发生的错误。您的 allies 列表将是所有实例之间共享的静态列表。而是使用

def __init__(self, name, allies=None):
        self.name = name
        self.allies = allies or []