""" This program is part of an exercise in Think Python: An Introduction to Software Design Allen B. Downey This program explains and corrects a bug in BadKangaroo.py. Before reading this, you should try to debug BadKangaroo. """ class Kangaroo(object): """a Kangaroo is a marsupial""" def __init__(self, contents=[]): # The problem is the default value for contents. # Default values get evaluated ONCE, when the function # is defined; they don't get evaluated again when the # function is called. # In this case that means that when __init__ is defined, # [] gets evaluated and contents gets a reference to # an empty list. # After that, every Kangaroo that gets the default # value get a reference to THE SAME list. If any # Kangaroo modifies this shared list, they all see # the change. # The next version of __init__ shows an idiomatic way # to avoid this problem. self.pouch_contents = contents def __init__(self, contents=None): # In this version, the default value is None. When # __init__ runs, it checks the value of contents and, # if necessary, creates a new empty list. That way, # every Kangaroo that gets the default value get a # reference to a different list. # As a general rule, you should avoid using a mutable # object as a default value, unless you really know # what you are doing. if contents == None: contents = [] self.pouch_contents = contents def __str__(self): """return a string representation of this Kangaroo and the contents of the pouch, with one item per line""" t = [ object.__str__(self) + ' with pouch contents:' ] for obj in self.pouch_contents: s = ' ' + object.__str__(obj) t.append(s) return '\n'.join(t) def put_in_pouch(self, item): """add a new item to the pouch contents""" self.pouch_contents.append(item) kanga = Kangaroo() roo = Kangaroo() kanga.put_in_pouch('wallet') kanga.put_in_pouch('car keys') kanga.put_in_pouch(roo) print kanga print '' print roo