In [7]:
# %load 17.06
# This exercise is a cautionary tale about one of the most common, and
# difficult to find, errors in Python.
# 1. Write a definition for a class named Kangaroo with the following methods:
# (a) An __init__ method that initializes an attribute named pouch_contents
# to an empty list.
# (b) A method named put_in_pouch that takes an object of any type and adds
# it to pouch_contents.
# (c) A __str__ method that returns a string representation of the Kangaroo
# object and the contents of the pouch.
# Test your code by creating two Kangaroo objects, assigning them to variables
# named kanga and roo, and then adding roo to the contents of kanga’s pouch.
# 2. Download thinkpython.com/code/BadKangaroo.py. It contains a solution to
# the previous problem with one big, nasty bug. Find and fix the bug.
# If you get stuck, you can download thinkpython.com/code/GoodKangaroo.py,
# which explains the problem and demonstrates a solution.
# Current Status: Incomplete
In [1]:
class Kangaroo(object):
def __init__(self):
self.pouch_contents = []
def put_in_pouch(self, thing):
self.pouch_contents.append(thing)
def __str__(self):
return "I have {} in my pouch".format(self.pouch_contents)
def __repr__(self):
return 'Kangaroo <{}>'.format(self.pouch_contents)
In [2]:
kanga = Kangaroo()
roo = Kangaroo()
In [3]:
kanga.put_in_pouch(5)
kanga.put_in_pouch("hello")
kanga.put_in_pouch(roo)
In [4]:
print(kanga)
In [5]:
roo.put_in_pouch("world")
In [6]:
print(kanga)
In [7]:
kanga
Out[7]:
In [8]:
print(roo)
In [9]:
roo
Out[9]:
In [10]:
"""
This program is part of an exercise in
Think Python: An Introduction to Software Design
Allen B. Downey
WARNING: this program contains a NASTY bug. I put
it there on purpose as a debugging exercise, but
you DO NOT want to emulate this example!
"""
class Kangaroo(object):
"""a Kangaroo is a marsupial"""
def __init__(self, contents=[]):
"""initialize the pouch contents; the default value is
an empty list"""
self.pouch_contents = contents
def __str__(self):
"""return a string representaion 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)
# If you run this program as is, it seems to work.
# To see the problem, trying printing roo.
In [11]:
print(roo)
In [14]:
"""
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)
In [ ]:
In [ ]: