19. Objects I — Introduction
Objects are a way to combine data and functionality together within our programs
Motivation for this is, it may help with abstraction and encapsulation
Further, you may find it a little more natural and analogous to how you think of the world
Consider the
List
s you have been using — these are objectsThey have some data associated with them,
Their size
The information stored in the list
But they also have functionality associated with them too
append
remove
You are already used to working with some objects (e.g.,
List
)But you have not defined your own objects
In this topic, the basics of how to define your own objects will be covered
19.1. Classes vs Objects
We are going to make
Circle
objectsHowever, in order to start making our own objects, we first must define a class
A class is simply the code that defines what it means for something to be an object of the class
For example, we will define a
Circle
class, which contains all the information needed for Python to start making instances ofCircle
sYou can think of the class as the blueprints for making objects
Going back to
List
sThere exists a class definition (blueprints) for
List
sWith the one class, I can then create as many instances of
List
s as I want
19.2. Circle Class
Just like the rest of the class, we will lean by doing
In other words, we will define the
Circle
class and then make a few instances ofCircle
objectsHowever, there is one big question — what is a circle; what data and functionality should it have?
Turns out, we get to invent this
We decide what data will be stored
We decide what functionality it will have
For our needs, we will have a
Circle
:Know its radius — this is an attribute, the data
Be able to perform basic geometry calculations — these are methods, the functionality
19.2.1. Starting the Class
To start writing our
Circle
class, we use theclass
keyword
1class Circle:
2 """
3 A class for representing circle based on its radius. The class provides functionality to perform basic geometry
4 calculations (diameter, area, circumference).
5 """
The above example contains the start of the class
The
class Circle:
starts the classAnything indented is part of the
Circle
class definitionLike how anything indented under an
if
is part of theif
block
The docstring comment is a simple description of the class
19.2.2. Constructor/Initialization and Attributes
With just the
class Circle
, we can actually start making instances of the class
1some_circle = Circle()
2print(type(some_circle)) # Results in something like <class '__main__.Circle'>
However, this is not particularly useful as we have yet to really describe the
Circle
class
19.2.2.1. Constructor
To start making the class useful, we will write a special function that tells Python how to setup the class for our needs
1class Circle:
2 """
3 A class for representing circle based on its radius. The class provides functionality to perform basic geometry
4 calculations (diameter, area, circumference).
5 """
6
7 def __init__(self):
8 """
9 Creates a Circle object with a radius of 0.
10 """
11 self.radius = 0
In the above example, we see the use of the special function called
__init__
, which describes how to initialize an instance of the classThe
__init__
method is called the constructor, or the initialization method
We can also see that we are creating an attribute called
radius
that will have the value0
upon the creation of aCircle
objectYou will notice a special variable called
self
in the parameter list and before the attributeradius
self
is a reference variable to this, the current instance of the class (itself)All methods within the class require that the first parameter is the
self
reference variableAdditionally, accessing any attributes or methods within the class require the use of the
self
reference variableThe
self
variable can feel a little weird at first, but it is something that will start to make sense as we go
With
__init__
written with the setup of the attributeradius
, we can now start to assign values
1circle_a = Circle()
2circle_b = Circle()
3
4circle_a.radius = 1
5circle_b.radius = 5
6
7print(circle_a.radius) # Results in 1
8print(circle_b.radius) # Results in 5
In the above example, we created two
Circle
objects and then assigned a value to their respectiveradius
attributesBoth
circle_a
andcircle_b
are of the classCircle
, but they are two separate instances of the class with two separateradius
attributes
19.2.2.2. Constructor Parameters
We can also include parameters for the
__init__
method, as seen below
1class Circle:
2 """
3 A class for representing circle based on its radius. The class provides functionality to perform basic geometry
4 calculations (diameter, area, circumference).
5 """
6
7 def __init__(self, radius: float):
8 """
9 Creates a Circle object with the specified radius.
10
11 :param radius: The radius of the Circle
12 :type radius: float
13 """
14 self.radius = radius
In the above example, we include a parameter for the
radius
, which will be used to set the attribute when aCircle
object is createdThis way we do not need to set the values ourselves after they are created, as seen in the following example
1circle_a = Circle(1)
2circle_b = Circle(5)
3
4print(circle_a.radius) # Results in 1
5print(circle_b.radius) # Results in 5
19.2.3. Functionality and Methods
The
Circle
class has the attributeradius
. but as of now, that’s all it can do — store a radius valueFurther, there are other features of a circle we may want to capture
Diameter of a circle
Area of a circle
Circumference of a circle
Fortunately, although these values are not stored within the
Circle
class as attributes, they can be calculated based on theCircle
'sradius
Consider the
diameter
method below that we could add to theCircle
class below__init__
1class Circle:
2
3 # init and/or other methods not shown for brevity
4
5 def diameter(self) -> float:
6 """
7 Calculate and return the diameter of the Circle based on its radius.
8
9 :return: diameter of the Circle
10 :rtype: float
11 """
12 return 2 * self.radius
The method itself is not overly sophisticated — the diameter of a circle is twice its radius
But you will notice, once again, the use of
self
Every method that belongs to the class must start with
self
in the parameter listSince we are accessing the specific
Circle
object’sradius
, we make use of the reference variableself
The following two methods follow the same pattern, but perform their respective calculations
1import math
2
3
4class Circle:
5
6 # init and/or other methods not shown for brevity
7
8 def area(self) -> float:
9 """
10 Calculate and return the area of the Circle based on its radius.
11
12 :return: Area of the Circle
13 :rtype: float
14 """
15 return math.pi * self.radius**2
16
17 def circumference(self) -> float:
18 """
19 Calculate and return the circumference of the Circle based on its radius.
20
21 :return: Circumference of the Circle
22 :rtype: float
23 """
24 return 2 * math.pi * self.radius
To make use of these methods, we call the method on the specific
Circle
object we want
1circle_a = Circle(1)
2circle_b = Circle(5)
3
4print(circle_a.area()) # Results in 3.141592653589793
5print(circle_b.circumference()) # Results in 31.41592653589793
In the above example, notice how the methods are called with parentheses
Also notice that, although the methods in the
Circle
class have theself
variable specified in its parameter list, no actual value is explicitly passed as an argument
When calling
circle_a.area()
, I am asking theCircle
object referenced bycircle_a
to calculate and return its areaSimilarly, when calling
circle_b.circumference()
, I am asking the instancecircle_b
to calculate and return its circumference
Note
Consider circle_a.area()
. The variable circle_a
is a reference to some Circle
object, and I am asking
for that instance to calculate and return its area
. Here, circle_a
and the self
variable from within the
Circle
class are referencing the same Circle
object. When looking at the area
method’s code, it makes
use of its attribute radius
, which is accessed via a reference variable to the instance of the Circle
object
the method was invoked on — self
.
19.2.4. Testing the Class
As always, we want to ensure our programs are correct, so we will write some tests
Unlike the
assert
tests we have done so far, we need to create instances of the objects first before we can test them
1circle_0 = Circle(0)
2assert 0 == circle_0.radius
3assert 0 == circle_0.diameter()
4assert 0 == circle_0.area()
5assert 0 == circle_0.circumference()
6
7circle_10 = Circle(10)
8assert 10 == circle_10.radius
9assert 20 == circle_10.diameter()
10assert 0.001 > abs(circle_10.area() - 314.1592)
11assert 0.001 > abs(circle_10.circumference() - 62.8319)
19.3. For Next Class
Download and look through the
Circle class