0

During experimenting, I had encountered a really bizarre problem which made me very confused. After creating several class objects by iterating through a range, I called a function from another class that would append 1 string to the primary class objects. After looking at all of the objects' lists, I saw that they were all the same, even though they should've been different, and there wasn't just one string for each class, but the number of strings matched the number of the class objects themselves.

class Stack():

    cards = []
    setUp = False

    def set_up(self):

        cardTypes = ["A", "B", "C", "D"]

        for cardType in cardTypes:
            for x in range(3):
                self.cards.append(cardType)

        self.setUp = True


    def deal(self, player, amount):

        if self.setUp:            
            for x in range(amount):
                card = self.cards[0]
                self.cards.remove(card)
                player.cards.append(card)

        else:
            self.set_up()
            self.deal(player, amount)


class Player():

    cards = []


class Game():

    def start(self):

        stack = Stack()

        players = [Player() for player in range(int(input("How many players?")))]

        for player in players:
            stack.deal(player, 1)

        for player in players:
            print(player.cards)
            #all players have the same numbers of cards (the amount of players = number of cards)
            #when all players should only have 1 card each since I put 1 in stack.deal
            #it's also as if all players become one when I call that function.

I ran the code using Game().start().

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Instead of telling us about your indentation, could you fix it? I'd do it myself, but I'm not exactly sure about the classes themselves. Are they inside the parent class, or are they separate? – zondo Apr 04 '17 at 15:18
  • Your indentation is still wring. I guess by "they were all the same" you mean "they have all the same `cards` attribute". Which is to be expected since `cards` is a class attribute. Maybe you want it to be an instance attribute. – Stop harming Monica Apr 04 '17 at 17:16
  • @Goyo Yes, they should all have the same class attribute "cards", though the attribute "cards" should only have one element in them - "A". –  Apr 04 '17 at 17:45
  • No. You have n players, you add n cards. – Stop harming Monica Apr 04 '17 at 18:05
  • @ChrisCroissant The function does not retain anything and does deal with one object at a time. But the `cards` attribute is always the same. Do you know what "class attribute" means? You seem to be somewhat confusing classes and instances. – Stop harming Monica Apr 04 '17 at 18:32
  • @Goyo Then how would I create a separate variable for every class object I create? I think you have found my problem. –  Apr 04 '17 at 18:35
  • `object.attribute = value` – Stop harming Monica Apr 04 '17 at 18:40

1 Answers1

1

This is a common error to people comming into Python from Java or C++: attributes declared at the class body are actually class attributes, and will be the same object visible for all instances of that class.

To create new and independent attributes for each instance of your class, you have to attribute them inside the __init__ method:

class Stack():
   def __init__(self):
        self.setup = False
        self.cards = []
   ...

(Also, another "Javaism" in there: not all code needs to run inside methods in Python - so, tehre is no sense in having a start method in the game class to be used as you do - if ther is a single method in it, just do away with the "Game" class and move that code to a function (def game(...):) and just call it to get going).

jsbueno
  • 99,910
  • 10
  • 151
  • 209