[Tutor] Methods defined in my class are affecting all the objects at runtime.

Peter Otten __peter__ at web.de
Sat Oct 29 17:26:02 CEST 2011


Brian Stovall wrote:

> Hello world!
> 
> I obviously don't understand something important and basic, but I am
> having trouble figuring it out myself... I am running python v3.2.2 on
> a Win XP machine.
> 
> My code:
> 
> import card_model
> import random
> 
> class Pile:
>     """An Object reperesenting a list of 'Card' Objects: could be a
> hand, discard pile, tableau
>     or anything really. Has a display_type that is used to clarify
> what kind of display to use, and
>     .deal(cards[] , new_pile(Pile Object)) and .shuffle() methods."""
> 
>     DISPLAY_TYPES = ["STACK", "FAN", "ACCORDION", "CASCADE"]
> 
>     def __init__(self, cards = [], display_type = "STACK"):

That is a common pitfall: the default values of functions and methods are 
evaluated only once. Therefore all Pile instances created without an 
explicit cards argument

p = Pile()

end up sharing the same cards list. The idiomatic way to avoid that problem 
is a default value of None:

    def __init__(self, cards=None, display_type="STACK"):
        if cards is None:
            cards = [] # no list provided -> make a new one
        self.cards = cards
        self.display_type = display_type

Note that this problem can only occur with "mutable" types (types whose 
internal state can be modified at any time); the default for display_type is 
immutable (its state is set once and for all when the object is created) and 
thus cannot cause that kind of trouble.

>         self.cards = cards
>         self.display_type = display_type
> 
>     def __str__(self):
>         return_string = ""
>         for i in self.cards:
>             return_string = return_string + str(i) + "\n"

Have a look at str.join(). Example:

"\n".join(str(card) for card in self.cards)

>         return_string = return_string + str(self.display_type)
>         return return_string
> 
>     def shuffle(self):
>         random.shuffle(self.cards)
> 
>     def add(self, card_list):
>         for i in card_list:
>             self.cards.append(i)

Have a look at list.extend().
 
>     def deal(self, number_of_cards, position = 0):
>         """Deletes the number of cards out of the pile, starting from
>         position (default is the top) and returns that list of cards, for
>         communication with other piles' .add methods."""
> 
>         dealt_list = []
>         try:
>             for i in range(number_of_cards):
>                     dealt_list.append(self.cards[position])
>                     del self.cards[position]

Have a look at list.pop() or slices like 

cards[position:position+number_of_cards]
 
>             return(dealt_list)
>         except IndexError:
>             print("Error, out of cards!")
> 
>             return(None)
> 
> I had been testing it with single objects favorably, but when I
> instantiate two Pile objects, methods like .add or .shuffle affect all
> of the Pile objects in memory. At first I thought the objects were all
> initializing to the same space in memory, but it wasn't true. If you
> need to see all my modules or my tester code, I will happily post.
> 
> Thanks for helping a rank beginner!
> 
> -Brian
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor




More information about the Tutor mailing list