Lecture 18 — Classes, Part 1¶
Overview¶
- Define our own types and associated functions
- Encapsulate data and functionality
- Raise the “level of abstraction” in our code
- Make code easier to write and test
- Reuse code
Potential Examples¶
In each of these, think about what data you might need to store to represent the “object” and what functionality you might need to apply to the data.
- Date
- Time
- Point
- Rectangle
- Student
- Animal
- Molecule
An Example from Earlier in the Semester¶
- Think about how difficult it was to keep track of the information about each restaurant in the Yelp data.
- You had to:
- Remember the indices of (a) the restaurant name, (b) the latitude and longitude, (c) the type of restaurant, (d) the address, etc.
- Form a separate list inside the list for the ratings.
- Write additional functions to exploit this information
- If we used a class to represent each restaurant:
- All of the information about the restaurant would be stored and accessed as named attributes
- Information about the restaurants would be accessed through functions that we write for the class.
Point2d Class¶
Simplest step is to just tell Python that
Point2d
will exist as a class, deferring the addition of information until later.class Point2d(object): pass
The Python reserved word
pass
says that this is the end of the class definition.- We will not need this later when we put information into the class.
Attributes¶
- Classes do not get interesting until we put something in them.
- The first thing we want is variables so that we can put data into a
class.
- In Python these variables are often called attributes.
- Other languages call them member variables.
- We will see three different ways to specify attributes.
Assigning Attributes to Each Instance¶
Points have an
x
and ay
location, so we can write, for example,from math import sqrt p = Point2d() p.x = 10 p.y = 5 dist_from_origin = sqrt(p.x**2 + p.y**2)
We have to do this for each class instance.
This is prone to mistakes:
- Could forget to assign the attributes
- Could accidentally use different names for what is intended to be the same attribute.
Example of an error
q = Point2d() q.x = -5 dist_from_origin = sqrt(q.x**2 + q.y**2) # q.y does not exist
Defining the Attributes Inside the Class¶
The simplest way to make sure that all variables that are instances of a class have the appropriate attributes is to define them inside the class.
For example, we could redefine our class as
class Point2d(object): x = 0 y = 0 pass
All instances of
Point2d
now have two attributes,x
andy
, and they are each initialized to 0.We no longer need the
pass
because there is now something in the class.
Defining the Attributes Through An Initializer / Constructor¶
We still need to initialize
x
andy
to values other than0
:p = Point2d() p.x = 10 p.y = 5
What we’d really like to do is initialize them at the time we actually create the
Point2d
object:p = Point2d(10,5)
We do this through a special function called an initializer in Python and a constructor in most other programming languages.
Inside the class this looks like
class Point2d(object): def __init__( self, x0, y0 ): self.x = x0 self.y = y0
Our code to create the point now becomes
p = Point2d(10,5)
Notes:
- Python uses names that start and end with two
'_'
to indicate functions with special meanings. We have already seen this with operators and we’ll see more soon. - The name
self
is special notation to indicate that the object itself is passed to the function.
- Python uses names that start and end with two
If we’d like to initialize the point to without passing these values to the constructor every time then we can specify default arguments
class Point2d(object): def __init__( self, x0=0, y0=0 ): self.x = x0 self.y = y0
allowing the initalization
p = Point2d()
Methods — Functions Associated with the Class¶
We create functions that operate on the class objects inside the class definition:
import math class Point2d(object): def __init__( self, x0, y0 ): self.x = x0 self.y = y0 def magnitude(self): return math.sqrt(self.x**2 + self.y**2) def dist(self, o): return math.sqrt( (self.x-o.x)**2 + (self.y-o.y)**2 )
these are called methods
This is used as
p = Point2d(0,4) q = Point2d(5,10) leng = q.magnitude() print "Magnitude %2f" %leng print "Distance is %2f", %p.dist(q)
Note that with the above definition of
Point2d
, the following is illegalq = Point2d(5,10) leng = magnitude(q) print "Magnitude %.2f" %leng
Exercise¶
Another special method/function — one that we have to write — is
__str__
which converts an object to a string. Write method__str__
for thePoint2d
so that it produces the following>>> q = Point2d(5,10) >>> print str(q) (5,10)
Write a new
Point2d
method calledscale
that takes as an input argument a single value and multiples both thex
andy
attributes by this value.
Classes and Modules¶
- Each class should generally be put into its own module, or several closely-related classes should be combined in a single module.
- During lecture we will place the code for
Point2d
into its own module. - Doing so is good practice for languages like C++ and Java, where classes are placed in separate files.
- Testing code can be included in the module or placed in a separate module.
Operators and Other Special Functions¶
We’d like to write code that uses our new objects in the most intuitive way possible.
For our point class, this involves use of operators such as
p = Point2d(1,2) q = Point2d(3,5) r = p+q s = p-q t = -s
Notice how in each case, we work with the
Point2d
variables (objects) just like we do with int and float variable (objects).We implement these by writing the special functions
__add__
,__sub__
, and__neg__
For example, inside the
Point2d
class we might havedef __add__(self,other): return Point2d(self.x + other.x, self.y+other.y)
Similarly, we can define boolean operators such as
==
and!=
through the special functions__eq__
and__neq__
Exercise¶
- Write the implementation of
__sub__
forPoint2d
- Write the implementation of
__neg__
forPoint2d
- Write the implementation of
__mul__
forPoint2d
- This function should be like the
scale
function, except it should create a new object instead of modifying an existing one.
- This function should be like the
- Write the implementation of
__eq__
forPoint2d
When to Modify, When to Create New Object¶
- Some methods, such as
scale
, modify a singlePoint2d
object - Other methods, such as our operators, create new
Point2d
objects without modifying existing ones. - The choice between this is made on a method-by-method basis by thinking about the meaning — the semantics — of the behavior of the method.
Programming Conventions¶
- Don’t create attributes outside the class.
- Don’t directly access or change attributes except through class
methods.
- Languages like C++ and Java have constructions that enforce this.
- In languages like Python it is not a hard-and-fast rule.
- Class design is often most effective by thinking about the required
methods rather than the required attributes.
- As an example, we rarely think about how the Python
list
anddict
classes are implemented.
- As an example, we rarely think about how the Python
Time Example¶
- In the remainder of the lecture, we will work through an extended
example of a
Time
class - By this, we mean the time of day, measured in hours, minutes and seconds.
- We’ll brainstorm some of the methods we might need to have.
- We’ll then consider several different ways to represent the time
internally:
- Hours, minutes and seconds
- Seconds only
- Military time
- Despite potential internal differences, the methods — or at least the
way we call them — will remain the same
- This is an example of the notion of encapsulation, which we will discuss more in Lecture 19.
- At the end of lecture, the resulting code will be posted and exercises will be generated to complete the class definition.
Summary¶
- Define new types in Python by creating classes
- Classes consist of attributes and methods
- Attributes should be defined and initialized through the special
method call
__init__
. This is a constructor - Other special methods allow us to create operators for our classes.
- We looked at a Point2d and Time example.