In ICS3U, we worked with floating point division and modulus, / and % respectively.
Now we have some new concepts to work with, floor division, //.
x = 5y = 2zz = x / y # this is division (floating point, "regular division") # what happened to the quotient?zz = str(zz)print('Floating point division: ' + zz)z = x // y # this is floor division (integer) # sometimes this is referred to as floor(ed) division # what happened to the quotient? # "The resultant value is a whole integer" (see python docs)z = str(z)print('Floor (Integer) division: ' + z)There's a bit of history and number theory that goes along with this. I'll start you down the rabbit hole. Thank you Mr. van Rossum!
A less mathematical look at this phenomenon is explained in the article, 'The Problem with Integer Division' as well. Thank you Mr. van Rossum, again!
Chapter 15. Floating Point Arithmetic: Issues and Limitations, in the Python Documentation, has a very good description of why this happens.
Python has built in capabilities to convert types. If you're ever unsure of the type, use the built-in function, type().
You have converted between data types during ICS3U when you wanted to print. The print() requires string types only.
x = 1.5print( str(x) )int()
int() will convert from the given type to an integer. In this example, floating point-to-integer and string-to-integer.
print(int(2.5))x = int('1')print(type(x))float()
float() will convert from the given type to a floating point number.
print(float(3))print(float('123'))str()
str() will convert from the given type to a string.
print(str(1.25))In Python, character-to integer and integer-to-character conversions are handled with the built-in functions ord() and chr(). Further type conversion may be necessary depending on what you want to do.
print(chr(97))print(ord('a'))x = chr(97)y = ord('a')print(type(x))print(type(y))This would be an appropriate time to look at an ASCII table.
In ICS3U, we looked at the comparison operators: <, >, <=, >=, == and !=.
How can we compare two strings in Python? ==.
Don't use the keyword is to test equality, it tests identity.
A case where you would use is? To check if two objects were the same, and by "same" we mean same memory address.
We will look at comparing objects later on in the course.
Finite data representation is thoroughly dealt with in chapter 15 of The Python Tutorial. Let's take a look at Floating Point Arithmetic: Issues and Limitations.
I would like you to fill out a K-W-L chart while you read the article. Can you identify integer bounds, precision of floating-point real numbers, and rounding errors?
In ICS3U, arrays were used to store data. Please take a look at the String or the Lists, aka Data Structures, aka Arrays notes for a refresher.
In ICS4U, we are going to use arrays with compound data types.
A compound data type is one which is created from other data types. For example, a string is a collection of characters.
Objects - An instance of a class (combination of data and functionality)
Structures - Arrays, Link Lists, Record
Records - used in databases
Object-Oriented Programming is a programming model (paradigm) where data (typically nouns) and functionality (typically verbs) are combined in a class. An instance (one time copy) of that class, is called an object.
In Python, everything is an object (remember the reference ('.') operator in ICS3U?) - more about that as the course unfolds...
In ICS3U we used a procedural paradigm to solve problems. In ICS4U we will use an OOP paradigm. Clearly, the term multi-paradigm programming language applies to Python. It's best to remember that the programmer chooses the problem solving approach - unless the assignment states otherwise!
(Image found on Reddit by Ethan K.)
When I defined an object, I did so by stating that it was a one time copy of a class. Then I defined class by stating it was a paradigm where data (typically nouns) and functionality(typically verbs) were combined to form a model. This is encapsulation. Encapsulation (data and functions joined) allows for data hiding. Data hiding is a concept that occurs when the program has a public side and a private side. The private side protects data that the programmer does not want the public side to have access to. Think and repeat to yourself: public methods, private data.
I would start by thinking about what a dog was.
How do I describe a dog?
Name, height, age, colour, weight ...
What does a dog do?
Run, sit, chase, bark, sleep ...
Looks like I needed nouns and verbs.
If I combine these nouns and verbs, I'd have a class. A blueprint if you will.
If I make a one time copy of the class Dog, I'd be making an object. Remember that an object is an instance of a class.
Now, I have an actual dog. It encapsulates data and functions. It can do things (functions) and it is described by the data it contains.
Notice how the class was capitalised, and the object wasn't. This is part of the naming convention in OOP.
Remember the reference operator ('.') from ICS3U?
That's how!
object_name.function() # the reference operator in action!snoopy.sit() #my Dog Class object snoopy, doing something.Take a look at this screenshot from a game.
Can you make a class to represent the player class?
What are the differences between the 4 characters?
Divide the problem into nouns and verbs. When you identify the nouns (data), jot down the type as well.
Can you make 4 objects?
Be ready to share your design with the class.
After you've read the intro OOP notes and done the screenshot exercise above, let's try to see it in practice.
I want to make a video game that revolves around a band. How do I model this in OOP?
Well, a band has members and it has a name. Let me start my Class
# The ideas for this all come from# the Python Documentation Project: https://docs.python.org/3/tutorial/classes.html# and Sloan Live at Massey Hall on YouTube# Sloan Live at Massey Hall: https://youtu.be/LkebgKJVmHwclass Band: members = 4 name = ''My class has 2 attributes (members, an integer and name, a string).
I can change an attribute of the class with assignment.
I can also make in an instance of the class. Instantiation is the creation of an object. An object is a one time copy of the class. It has all the attributes (data) and functions (methods) of that class. I'm going to build an object. My object is called 'sloan' . Note the case I used in the naming convention of the class and the object (upper case vs lower case).
sloan = Band()sloan was built under the definition of my class Band.
I can change an attribute by using the assignment operator. When I want to see that attribute, I use the reference operator.
sloan.name = 'SLOAN'print(sloan.name)This is not very useful right now, let's see how this could be more productive.
My class can be have values set when the instance is created. This allows me to customize my object when it is built.
An important concept in OOP is called the Constructor. Think of the constructor like a special method that builds the object of the class. My first version of class Band does not have a constructor. But clearly, there must have been one present, because the object exists.
In Python the constructor looks like this
def __init__(self):The constructor you write will OVERRIDE the default (invisible) constructor. My constructor allows me to make sure I have room to store the names of the a band's members.
# The ideas for this all come from# the Python Documentation Project: https://docs.python.org/3/tutorial/classes.html# and Sloan Live at Massey Hall on YouTube# Sloan Live at Massey Hall: https://youtu.be/LkebgKJVmHwclass Band: members = 4 name = '' def __init__(self): self.memberNames = []sloan = Band()sloan.name = 'SLOAN'print(sloan.name)My class still looks clunky. I should be able to take care of the attributes members and name in the constructor.
To do this I am going to pass multiple parameters to my constructor. I'm also going to move the two attributes (members and name) to the inside of the constructor. Because the band can be a different size, I also changed the starting value of members to 0 (zero). I can change this when I make my object.
# The ideas for this all come from# the Python Documentation Project: https://docs.python.org/3/tutorial/classes.html# and Sloan Live at Massey Hall on YouTube# Sloan Live at Massey Hall: https://youtu.be/LkebgKJVmHwclass Band: def __init__(self): self.memberNames = [] members = 0 name = ''sloan = Band()sloan.name = 'SLOAN'print(sloan.name)I need to modify my constructor so that I can set up those attributes dynamically (like when the object is created). I also need to use the keyword self to link the attributes listed in the constructor to the one in the actual class.
# The ideas for this all come from# the Python Documentation Project: https://docs.python.org/3/tutorial/classes.html# and Sloan Live at Massey Hall on YouTube# Sloan Live at Massey Hall: https://youtu.be/LkebgKJVmHwclass Band: def __init__(self, memberNames, members, name): self.mN = memberNames self.m = members self.n = namesloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')Notice how the band was built. Do you see where the values for the attributes go? Let's print the member's names.
print(sloan.mN)Did the values go where you wanted them to?
Data Attributes don't need to be declared to be used. They will appear when you make them, and then go when you are done.
For instance, I want to keep track of how many EP's the band has.
class Band: def __init__(self, memberNames, members, name): self.mN = memberNames self.m = members self.n = namesloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')sloan.ep = 1sloan.ep = sloan.ep + 2print(sloan.ep)Notice how there is no attribute for EP's in the class design, but I can add them to the instance. I can delete these added attributes with the del keyword.
class Band: def __init__(self, memberNames, members, name): self.mN = memberNames self.m = members self.n = namesloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')sloan.ep = 1sloan.ep = sloan.ep + 2print(sloan.ep)del sloan.epprint(sloan.ep) # THIS SHOULD CRASH If I remove the EP's counter, it's gone.
I tend to use the word method and function interchangeably. Specifically, a method is a function that "belongs to" an object. I'm going to add a method called checkMic(). It will be called by the object.
class Band: def __init__(self, memberNames, members, name): self.mN = memberNames self.m = members self.n = name def checkMic(self): return 'check'sloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')var = sloan.checkMic()print('The first time we did a mic check:', var)The instance object is passed as the first argument of the function. Take a look at the second time we do a mic check.
sloan.checkMic is a method object NOTICE THE MISSING BRACKETS. It was stored in checkMic, and was used in the for loop.
class Band: def __init__(self, memberNames, members, name): self.mN = memberNames self.m = members self.n = name def checkMic(self): return 'check'sloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')var = sloan.checkMic()print('The first time we did a mic check:', var)checkMic = sloan.checkMicfor counter in range(3): print('The second mic check:', checkMic())What happened? The function was called without an argument. The instance object is passed as the first argument of the function.
The call sloan.checkMic() is equivalent to Band.checkMic(sloan). Take a look at the last line in the next example.
class Band: def __init__(self, memberNames, members, name): self.mN = memberNames self.m = members self.n = name def checkMic(self): return 'check'sloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')var = sloan.checkMic()print('The first time we did a mic check:', var)checkMic = sloan.checkMicfor counter in range(3): print('The second mic check:', checkMic())print(Band.checkMic(sloan))Instance variables are for data unique to each instance.
Class variables are for attributes and methods shared by all instances of the class.
class Band: style = 'Power-pop' # class variable shared by all instances def __init__(self, memberNames, members, name): self.mN = memberNames # instance variable unique to each instance self.m = members self.n = namesloan = Band(['Chris','Jay','Patrick','Andrew'], 4, 'SLOAN')myBand = Band(['Me','My Loop Petal','my Mac'], 3, 'Billy Shakes and the Spears')print(sloan.style) # shared by all bandsprint(myBand.style) # shared by all bandsprint(sloan.n) # unique to sloanprint(myBand.n) # unique to my bandMutability (the ability to change things) was an idea that you learned last year when we talked about lists and strings (and by extension dictionaries). Watch how a poor OOP design can lead to unexpected behaviour. Watch where I make my list that stores the member's names.
class Band: memberNames = [ ] # BAD OOP DESIGN def __init__(self, name): self.n = name def addMemberNames(self, memberName): self.memberNames.append(memberName)sloan = Band('SLOAN')myBand = Band('Billy Shakes and the Spears')sloan.addMemberNames(['Chris','Jay','Patrick','Andrew'])myBand.addMemberNames(['Me','My Loop Petal','my Mac'])print('The members of', myBand.n, 'are', myBand.memberNames) # WHAT ??I should have used an instance variable to hold the member's names. This way EACH band has its OWN members.
class Band: def __init__(self, name): self.n = name self.memberNames = [ ] # a list for the names of the members in each band def addMemberNames(self, memberName): self.memberNames.append(memberName)sloan = Band('SLOAN')myBand = Band('Billy Shakes and the Spears')sloan.addMemberNames(['Chris','Jay','Patrick','Andrew'])myBand.addMemberNames(['Me','My Loop Petal','my Mac'])print('The members of', myBand.n, 'are', myBand.memberNames) Some parting remarks from the Python Documentation:
class Band: def __init__(self, name): self.n = name self.memberNames = [ ] def addMemberNames(self, memberName): self.memberNames.append(memberName) def addAnotherMember(self, x): self.addMemberNames(x)sloan = Band('SLOAN')sloan.addMemberNames(['Chris','Jay','Patrick','Andrew'])sloan.addAnotherMember('sir')print(sloan.memberNames)I made it, right?
LET'S LEARN PYTHON - BASICS #8 OF 8 - CLASSES.
Please note that this great video was written in Python 2.x
Adjust your code to reflect the changes in print()
Inheritance allows the class you are writing to inherit features from a base class.
I need to modify the way I was solving my band situation. It turns out that all bands are share common attributes and functions. It doesn't matter what the genera of music is.
class Band(object): def practice(self): print('Ok, practice!')class RockBand(Band): passmyBand = RockBand() # I want a rock band, but it turns out a rock band, is a band.myBand.practice() # so when my band can practice like ALL bands canLet's put the constructor to some use. Let's assume that the minimum number of people in a band is 1. So, when I make my band, it inherits this from the base class.
class Band(object): def __init__(self): self.members = 1class RockBand(Band): def __init__(self): super(RockBand, self).__init__() #calls the init of the base classmyBand = RockBand() print(myBand.members)Can we inherit from multiple classes? It also looks like my band, IS A band, and HAS A home town.
class Band(object): def __init__(self, name): self.members = 1 self.name = name def printName(self): print(self.name)class RockBand(Band): def __init__(self, name, homeTown): super(RockBand, self).__init__(name) self.homeTown = HomeTown(homeTown)class HomeTown: def __init__(self, homeTown): self.name = homeTownmyBand = RockBand('Billy Shakes and the Spears','Toronto')myBand.printName()print(myBand.homeTown.name)LET'S LEARN PYTHON #10 - INHERITANCE - OOP 1 OF 3.
Please note that this great video was written in Python 2.x
Adjust your code to reflect the changes in print()
LET'S LEARN PYTHON #11 - OVERRIDING & FILE MANAGEMENT. - OOP 2 OF 3.
The challenge at the end of the video can be handled in two ways.
Multiple classes in one file or multiple files each with one class.
If you split your work into multiple files, please add from file import class where file is the name of your file without the .py extension, and class is the name of the class.
This is first line of your code. Your two files must be in the same directory.
This is an interesting idea. The syntax changed between Python 2.x and 3.x (Thanks Jacob!). Please read the Python documentation if you want to try the challenge (human - robot - cyborg) at the end of the video. I hid the video in that link. This is an optional lesson.
But why solve it with OOP? It's just another way of solving a problem.
Take a look at this Python-centric example Why is Object-Oriented Programming Useful? (With a Role Playing Game Example) from Invent with Python.
Learntofish's Blog has a very good 10 part tutorial. Please read past Tutorial: Object Oriented Programming in Python – Part 1
Unified Modeling Language allows you to visualize the structure of your classes and objects, and their relationships to other classes and objects. This is a simple tutorial that will help you with the OOP problem set, and eventually with the Software Management Unit.
I'm going to use GOOGLE DRAWINGS to make my UML shapes.
1. This is a rectangle in a rectangle. Drawings has a 'snap-to-fit' indicator that tells you when you are approaching the bounding area of the shape or the centre. It's handy for lining things up.
2. There are 3 text boxes
3. When I was done, I selected the whole image, right clicked, and selected GROUP. This lets me move the 5 elements together.
1. These are arrows.
2. When you draw them, drag your mouse towards your destination.
3. After you draw one, you will need to change the line end.
4. Only use these arrow pointers.
5. I also increased the line weight for this example.
UML gets complicated quickly. The point is for you to be able to sketch out your ideas visually. The last video will reinforces these ideas again.
Optional resources if you'd like to explore these ideas further:
LET'S LEARN PYTHON #13 - UML - UNIFIED MODELING LANGUAGE.
Use GOOGLE DRAWINGS (School or Personal Account)