Week 13: Writing Classes
Week 13 Goals
-
More understanding of writing classes
-
Understand how one class can use instances of another
Get Week 13 In-class Code
To copy over the week 13 in-class example programs, do the following (If you have trouble with either of these steps, ask a Ninja or your professor for help):
-
Create a w13-more-classes subdirectory in your
cs21/inclass
directory, and cd into it:$ cd ~/cs21/inclass $ mkdir w13-more-classes $ cd w13-more-classes $ pwd /home/yourusername/cs21/inclass/w13-more-classes
-
Copy over the week 13 files into your
w13-more-classes
subdirectory (check that they copied successfully copied by runningls
:$ cp ~admin21/public/w13-more-classes/*.py ./ $ ls bankaccount.py
Week 13 Files
-
bankaccount.py
- defines and uses a BankAccount class
Relationships Between Classes
One of the powerful things about object-oriented programming and being able to define our own custom classes is that we can aggregate them into more complex structures.
In this example, we’ll create a class Playlist
which represents a collection of Song
objects.
First, here’s the definition of the Song
class:
"""
Class that represents a song.
"""
class Song:
def __init__(self, artist, title, duration, year):
"""
Constructor. Creates a new instance of a Song.
Parameters:
* self: refers to this object
* artist (str): the name of the person/group who recorded the song
* title (str): the name of the song
* duration (int): the length of the song in seconds
* year (int): the year in which the song was recorded
"""
self.artist = artist
self.title = title
self.duration = duration
self.year = year
def getArtist(self):
return self.artist
def getTitle(self):
return self.title
def getDuration(self):
return self.duration
def getYear(self):
return self.year
Now we can create a class Playlist
that includes a list of Song
objects as one of its instance variables:
"""
Class that represents a playlist consisting of multiple songs.
The fields are as follows:
* name (str): the name given to the playlist
* songs (list): a list of Song objects
"""
from song import *
class Playlist:
# TODO: define a constructor that allows the caller to set the name
# The list of songs should be initialized to an empty list
def __init__(self, name):
"""
Constructor to create a Playlist with the given name.
The list of songs is initialized to an empty list.
"""
self.name = name
self.songs = []
def getName(self):
return self.name
def getSongs(self):
return self.songs
def addSong(self, song):
"""
Adds a song to the playlist.
Parameters:
* self: this object
* song (Song): object to add to list of songs
Returns: None. The Song is added to the list of songs
"""
self.songs.append(song)
def getTotalDuration(self):
"""
Calculates the total duration of all songs in the playlist.
Parameter:
* self: this object
Returns: sum of durations of all songs in list (float)
"""
total = 0
for song in self.songs:
total = total + song.getDuration()
return total
Now we can write code that uses these classes:
def main():
s1 = Song("Carly Rae Jepsen", "Call Me Maybe", 193, 2012)
s2 = Song("Taylor Swift", "Shake It Off", 219, 2014)
p = Playlist("Happy music")
p.addSong(s1)
p.addSong(s2)
print(p.getTotalDuration())
Having One Class Use an Instance of the Same Class
In the previous example, we saw that one class (Playlist
) used an instance of another (Song
).
But we can also have one class use an instance of the same class.
For instance, let’s say we have a BankAccount
class like this:
"""
Class to represent a bank account.
"""
class BankAccount:
def __init__(self, name):
"""
Constructor to create new BankAccount instance.
In addition to initializing the name, the BankAccount's
balance is initialized to 0
"""
self.name = name
self.balance = 0.0
def getName(self):
return self.name
def getBalance(self):
return self.balance
def deposit(self, amount):
"""
Attempts to make a deposit to the BankAccount.
Increases the balance by the amount, assuming the amount is positive.
Otherwise, does not modify the balance.
Parameters:
* self: refers to this object
* amount (float): amount to be deposited
Returns (boolean): whether or not the balance was modified.
"""
if (amount <= 0):
return False
else:
self.balance = self.balance + amount
return True
def withdraw(self, amount):
"""
Attempts to withdraw from the BankAccount.
Decreases the balance by the amount, assuming the amount is positive
but is not greater than the balance (i.e. the resulting balance
cannot be negative).
Otherwise, does not modify the balance.
Parameters:
* self: refers to this object
* amount (float): amount to be withdrawn
Returns (boolean): whethe or not the balance was modified.
"""
if (amount <= 0 or amount > self.balance):
return False
else:
self.balance = self.balance - amount
return True
def transfer(self, amount, other):
"""
Attempts to transfer money from this BankAccount to the other one.
Will only do so if the amount is positive and is not greater than
this object's balance.
Otherwise, the balances are not modified.
Parameters:
* self: refers to this object
* amount (float): amount to be transferred
* other (BankAccount): account to which money should be transferred
Returns (boolean): whethe or not transfer was made.
"""
if (amount <= 0):
return False
elif (amount > self.balance):
return False
else:
self.withdraw(amount)
other.deposit(amount)
return True
Note that the transfer
method takes a parameter of another instance of the BankAccount
class. This is okay, because this method can differentiate between the object on which it is called (self
) and the one that is passed as an argument (other
).
So now we can transfer money from one BankAccount
to another like this:
def main():
b1 = BankAccount("Bingo")
b1.deposit(100)
b2 = BankAccount("Bluey")
b2.deposit(400)
b1.transfer(50, b2) # transfers from b1 to b2
print(b1.getBalance()) # Bingo should now have $50
print(b2.getBalance()) # Bluey should now have $450