0%

cs61a-disc06

OOP

We now want to write three different classes, Mailman, Client, and Email to simulate email. Fill in the definitions below to finish the implementation! There are more methods to fill out on the next page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Email:
"""Every email object has 3 instance attributes: the
message, the sender name, and the recipient name.
"""
def __init__(self, msg, sender_name, recipient_name):
self.message = msg
self.sender_name = sender_name
self.recipient_name = recipient_name

class Mailman:
"""Each Mailman has an instance attribute clients, which
is a dictionary that associates client names with
client objects.
"""
def __init__(self):
self.clients = {}
def send(self, email):
"""Take an email and put it in the inbox of the client
it is addressed to.
"""
client = self.clients[email.recipient_name]
client.receive(email)

def register_client(self, client, client_name):
"""Takes a client object and client_name and adds it
to the clients instance attribute.
"""
self.clients[client_name] = client

class Client:
"""Every Client has instance attributes name (which is
used for addressing emails to the client), mailman
(which is used to send emails out to other clients), and
inbox (a list of all emails the client has received).
"""
def __init__(self, mailman, name):
self.inbox = []
self.name = name
self.mailman = mailman
self.mailman.register_client(self, self.name)
def compose(self, msg, recipient_name):
"""Send an email with the given message msg to the
given recipient client.
"""
email = Email(msg, self.name, recipient_name)
self.mailman.send(email)
def receive(self, email):
"""Take an email and add it to the inbox of this
client.
"""
self.inbox.append(email)

Inheritance

Python classes can implement a useful abstraction technique known as inheritance.
To illustrate this concept, consider the following Dog and Cat classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Dog(object):
def __init__(self, name, owner):
self.is_alive = True
self.name = name
self.owner = owner
def eat(self, thing):
print(self.name + " ate a " + str(thing) + "!")
def talk(self):
print(self.name + " says woof!")
class Cat(object):
def __init__(self, name, owner, lives=9):
self.is_alive = True
self.name = name
self.owner = owner
self.lives = lives
def eat(self, thing):
print(self.name + " ate a " + str(thing) + "!")
def talk(self):
print(self.name + " says meow!")

Notice that because dogs and cats share a lot of similar qualities, there is a lot of repeated code! To avoid redefining attributes and methods for similar classes, we can write a single superclass from which the similar classes inherit. For example, we can write a class called Pet and redefine Dog as a subclass of Pet:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Pet(object):
def __init__(self, name, owner):
self.is_alive = True # It's alive!!!
self.name = name
self.owner = owner
def eat(self, thing):
print(self.name + " ate a " + str(thing) + "!")
def talk(self):
print(self.name)

class Dog(Pet):
def talk(self):
print(self.name + ' says woof!')

Inheritance represents a hierarchical relationship between two or more classes where one class is a more specific version of the other, e.g. a dog is a pet. Because Dog inherits from Pet, we didn’t have to redefine init or eat. However, since we want Dog to talk in a way that is unique to dogs, we did override the talk method.

Questions

2.1 Below is a skeleton for the Cat class, which inherits from the Pet class. To complete the implementation, override the __init__ and talk methods and add a new lose_life method.
Hint: You can call the init method of Pet to set a cat’s name and owner.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Cat(Pet):
def __init__(self, name, owner, lives=9):
Pet.__init__(self, name, owner)
self.lives = lives
def talk(self):
""" Print out a cat's greeting.
>>> Cat('Thomas', 'Tammy').talk()
Thomas says meow!
"""
print(self.name + ' says meow!')
def lose_life(self):
"""Decrements a cat's life by 1. When lives reaches zero, 'is_alive' becomes False.
"""
if self.lives > 0:
self.lives -= 1
if self.lives == 0:
return False
else:
print("This cat has no more lives to lose!")

2.2 More cats! Fill in this implemention of a class called NoisyCat, which is just like a normal Cat. However, NoisyCat talks a lot – twice as much as a regular Cat!

1
2
3
4
5
6
7
8
9
10
11
12
13
class NoisyCat(Cat): # Fill me in!
"""A Cat that repeats things twice."""
def __init__(self, name, owner, lives=9):
# Is this method necessary? Why or why not?
Cat.__init__(self, name, owner, lives)
def talk(self):
"""Talks twice as much as a regular cat.
>>> NoisyCat('Magic', 'James').talk()
Magic says meow!
Magic says meow!
"""
for _ in range(2):
Cat.talk(self)