Arvin Johansson Arbab
Arvin Johansson Arbab

Reputation: 107

Python appending to two lists when it should only append to one

I have a list called teams which contains two objects, these are objects of the same class and they both have a "members" list. I am appending to these lists individually. See Fight.AddParticipant but the two participant objects I'm appending seem to end up in both of the team objects, which is unintended behavior. Why is this happening?

Code:

class Fight:
    participants = []
    teams = []
    attacked = []
    fighting = 0

    def MakeTeams(self, team):
        self.teams.append(team)

    def NumParticipants(self, teamnum = None):
        if (teamnum != None):
            return len(self.teams[teamnum].members)
        else:
            return len(self.participants)


    def AddParticipant(self, participant, team):
        self.participants.append(participant)
        ref = self.participants[-1]
        self.teams[team].members.append(ref)
        # print self.teams[1].members[0].name

    def SetFighting(self):
        self.fighting = self.NumParticipants()

    def AnnounceFight(self):
        print 'A battle between', self.NumParticipants(), 'fighters has begun!\n\n'
        self.AnnounceTeams()

    def AnnounceTeams(self):
        print ''
        for team in self.teams:
            print "Team name:", team.name
            print "Team morale:", team.morale
            for member in team.members:
                print member.name


class Participant:
    name = ""
    race = ""
    sex = ""
    hp = 0
    strength = 0
    agility = 0
    weapon = ""
    alive = True

    def __init__(self, name, race, sex, hp, strength, agility, weapon, alive = True):
        self.name = name
        self.race = race
        self.sex = sex
        self.hp = hp
        self.strength = strength
        self.agility = agility
        self.weapon = weapon
        self.alive = alive


class Team:
    name = ""
    members = []
    morale = 0

    def __init__(self, name, morale):
        self.name = name
        self.morale = morale

Fight = Fight()
Fight.MakeTeams(Team('Smart', 1))
Fight.MakeTeams(Team('Dumb', 1))
Fight.AddParticipant(Participant("Foo", "Human", "Female", 15, 15, 20, "Knife"), 0)
Fight.AddParticipant(Participant("Bar", "Human", "Male", 15, 15, 20, "Sabre"), 1)
Fight.SetFighting()
Fight.AnnounceFight()

Upvotes: 0

Views: 327

Answers (3)

Sergiy Migdalskiy
Sergiy Migdalskiy

Reputation: 1096

I think you mean members to be a member of an instance, but instead making them class members. Try this:

class Team:
    name = ""
    morale = 0

    def __init__(self, name, morale):
        self.members = []
        self.name = name
        self.morale = morale

You probably want to move all the other variables into constructors rather than keeping them as class variables. Class variables are shared by all instances and owned by class.

Upvotes: 0

agf
agf

Reputation: 176750

In all of your classes, you want to initialize instance variables like this:

def __init__(self):
    self.participants = []
    self.teams = []
    self.attacked = []
    self.fighting = 0

That way, they are separate for each fight, participant, team instead of shared for all fights, participants, or teams.

Upvotes: 3

Keith
Keith

Reputation: 43024

You have made the lists as class attributes, which means the lists are shared by all instances. It's the same list. You should make the lists instance attributes. Do that by creating them in the __init__ (constructor) method of the class.

Upvotes: 3

Related Questions