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
Lists 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
appendremove
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
CircleobjectsHowever, 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
Circleclass, which contains all the information needed for Python to start making instances ofCirclesYou can think of the class as the blueprints for making objects
Going back to
ListsThere exists a class definition (blueprints) for
ListsWith the one class, I can then create as many instances of
Lists 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
Circleclass and then make a few instances ofCircleobjectsHowever, 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
Circleclass, we use theclasskeyword
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
Circleclass definitionLike how anything indented under an
ifis part of theifblock
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
Circleclass
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
radiusthat will have the value0upon the creation of aCircleobjectYou will notice a special variable called
selfin the parameter list and before the attributeradiusselfis a reference variable to this, the current instance of the class (itself)All methods within the class require that the first parameter is the
selfreference variableAdditionally, accessing any attributes or methods within the class require the use of the
selfreference variableThe
selfvariable 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
Circleobjects and then assigned a value to their respectiveradiusattributesBoth
circle_aandcircle_bare of the classCircle, but they are two separate instances of the class with two separateradiusattributes
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 aCircleobject 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
Circleclass 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
Circleclass as attributes, they can be calculated based on theCircle'sradiusConsider the
diametermethod below that we could add to theCircleclass 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
selfEvery method that belongs to the class must start with
selfin the parameter listSince we are accessing the specific
Circleobject’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
Circleobject 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
Circleclass have theselfvariable specified in its parameter list, no actual value is explicitly passed as an argument
When calling
circle_a.area(), I am asking theCircleobject referenced bycircle_ato calculate and return its areaSimilarly, when calling
circle_b.circumference(), I am asking the instancecircle_bto 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
asserttests 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