Lesson Notes
Why use classes?
If a class
is a container for data, why use a class
instead of a list
or dictionary
?
We can think of a class as a self-contained sub-program that has:
A method is a function that can only be called on 1 type
of object:
The following method call works because the internal algorithm knows how to use the turtle object
turtle.forward(50)
However, if we called the same method on a different object:
mylist = []
mylist.forward(50) # !ERROR
This will not work because list
does not have a method called forward
and the forward
method from turtle only works with turtle
objects.
Methods are functions that require an object of specific type
class
vs dictionary
Classes encapsulate data and behavior, while dictionaries only hold data; however, in Python, classes keep track of their data using an internal dictionary object:
print(myobj.__dict__)
When we call a method on an object, the method has access to all the data stored in that object:
mystr = "ThIs StRiNg Is WEirD"
upper = mystr.upper()
lower = upper.lower()
print(upper, lower)
ord('s') #function
s.lower() #method
Let's write a version of the string class that saves a string as a list of ints, then converts it back as needed:
class Str:
def __init__(self, chars):
self.string_nums = []
for ch in chars:
self.string_nums.append(ord(ch))
def get_str(self):
mystr = ""
for ch in self.string_nums:
mystr += chr(ch)
return mystr
myobj = Str("Hello")
print(myobj.string_nums) # string_nums still exists after the __init__ returns, object scope
print(myobj.get_str())
While this class is kind of useless right now, it does illustrate a point.
Anything saved with self.
has object scope, meaning it can access any data stored in the object. So to create an instance variable, use self.<var name>
, where <var name>
is any valid python variable name.
Whenever accessing an instance variable or method in the class, you must use self.
:
def printdata(self):
print(self.myvar)
Objects are Mutable, so they can be changed and updated. Let's extend our Point
class with a new method:
class Point:
def __init__(self, x=0, y=0, color=[255, 0, 0]):
self.x = x
self.y = y
self.color = color
def set_to_comp_color(self):
red_comp = 255 - self.color[0]
blue_comp = 255 - self.color[1]
green_comp = 255 - self.color[2]
self.color = [red_comp, blue_comp, green_comp]
def main():
p1 = Point()
print(p1.x, p1.y, p1.color)
p1.set_to_comp_color()
print(p1.x, p1.y, p1.color)
main()
Notice the following method call
p.set_to_comp_color()
And the method being called
def set_to_complimentary_color(self):
#…code
There’s a mismatch for parameters. The caller of set_to_complimentary_color()
does not seem to give an argument for the self parameter.
self
comes before the dot, but Python conceptually changes it to:
point.set_to_complimentary_color()
=> set_to_complimentary_color(point)
Methods can return values just like any other function (including another object of the same class). Let's add a method that take another point as a parameter and creates a new point between the two:
def halfway(self, target):
mx = (self.x + target.x) / 2
my = (self.y + target.y) / 2
return Point(mx, my)
mid = p.halfway(q)
Let's make a Graph using our points.
First, we need to think about what kind of data the two dimensional Graph will have and what it can do.
Requirements:
import turtle
import point
class Graph:
def __init__(self, points=None, width=200, height=200):
self.width = width
self.height = height
self.points = points
self.window = turtle.Screen()
self.window.setworldcoordinates(-self.width, -self.height, self.width, self.height)
self.plotter = turtle.Turtle()
def drawAxis(self):
self.plotter.home()
self.plotter.up()
self.plotter.hideturtle()
self.plotter.goto(-self.width, 0)
self.plotter.down()
#draw the x-axis
self.plotter.forward(self.width*2)
self.plotter.up()
self.plotter.goto(0, self.height)
self.plotter.setheading(270)
self.plotter.down()
#draw the y axis
self.plotter.forward(self.height*2)
def plotGraph(self):
self.drawAxis()
self.plotter.up()
for p in self.points:
self.plotter.goto(p.x, p.y)
self.plotter.dot(3, p.color)
def clearGraph(self):
self.drawAxis()
self.plotter.clear()
self.points = []
def addPoint(self, x=0, y=0, label=""):
p = point.Point(x, y, label)
self.points.append(p)