A Python class defines a way of organizing code into containers of data, and functions that transform the data in some way. Once a class is instantiated in code, it becomes an object (and is usually assigned to a variable).
Below is a class definition named Shape
. It stores the data attribute shape
which is just a string. The only member function implemented in this class is the special __str__
function which returns the string I am a shape
when called on an object instantiated from the class Shape
.
The functions __init__
and __str__
both have special meanings in Python. __init__
is automatically called when an object is instantiated. Any code placed in this function will be automatically run. __str__
is a special function that is called when the print
function is called on an object.
class Shape():
def __init__(self):
self.shape = 'shape'
def __str__(self):
return "I am a {}.".format(self.shape)
Now we will instantiate the class and store it in an object with the variable name s
. Then we call the print statement giving s
as and argument and it automatically runs the __str__
function and returns its result.
s = Shape()
print(s)
Class inheritance
Now we will derive a class from Shape
called Polygon
. A Polygon
is a Shape
and therefore all of the functions defined in Shape
will work on an instantiated object of Polygon
(unless they are explicitly overridden).
We will also implement some new functions, not defined in Shape
that can compute the perimeter of a polygon and return the number of edges.
There is also a new data attribute called side_lengths
which is initialized to None
. We can't set its exact value yet because we don't have enough information about the polygon, e.g. How many sides it has, but we need to define it in order to define compute_perimeter
because it requires side_lengths
as an argument. Same goes for get_number_of_sides
.
Notice that Shape
is placed as an argument in the class definition of Polygon
, this indicates that Polygon
is derived from or inherited from Shape
. Also notice that class data attributes always start with self
.
class Polygon(Shape):
def __init__(self):
self.shape = 'polygon'
self.side_lengths = None
def compute_perimeter(self):
return sum(self.side_lengths)
def get_number_of_edges(self):
return len(self.side_lengths)
Now we can instantiate a Polygon
object called p
and call print
on it. It returns the function call from __str__
that is only defined in Shape
because a Polygon
is a Shape
.
p = Polygon()
print(p)
We can now derive another class from Polygon
, this time we are specialized enough that we know a Rectangle
has 4 sides, so we can give a default value for the data attribute side_length
.
class Rectangle(Polygon):
def __init__(self):
self.shape = 'rectangle'
self.side_lengths = [1, 1, 1, 1]
And now we can call compute_perimeter
on the object rect
that was instantiated from Rectangle
even though we didn't define the function in the Rectangle
class. We can do this because a Rectangle
is a Polygon
.
rect = Rectangle()
rect.compute_perimeter()
Likewise, we can derive a Triangle
class from Polygon
and it inherits the member functions from both Polygon
and Shape
. Again, a Triangle
is a Polygon
which is a Shape
.
class Triangle(Polygon):
def __init__(self):
self.shape = 'triangle'
self.side_lengths = [2, 2, 2]
Examples of calling functions on the object t
instantiated from Triangle
.
t = Triangle()
t.compute_perimeter()
t.get_number_of_edges()
print(t)
Everything in Python is an object. Including the lists we've already been using. This might help you understand the syntax of the sort
function a little better now.
x = [20, 4, 100]
x.sort()
x
You can also define classes that take arguments similar to the way regular functions do. Both classes and functions that are members of a class must use self
as their first argument. After that you can use arguments as you normally would, including keyword arguments and variable arguments.
class Car():
def __init__(self, number_of_doors=2):
self.number_of_doors = number_of_doors
def __str__(self):
if self.number_of_doors == 2:
return "I am a coupe."
if self.number_of_doors == 4:
return "I am a sedan."
else:
return "I don't know what kind of car I am."
An example of instantiating the Car()
class with different arguments that alter it's behavior.
c = Car()
print(c)
s = Car(4)
print(s)
s = Car(3)
print(s)
Python classes offer a way to organize your code and when used carefully can add readability and reuse to the code you write. However, if inheritance trees become too deep (classes inherit from classes, that inherit from classes, that inherit from classes, that inherit from classes, etc.) or multiple inheritance is used too frequently, the opposite can happen.
Further reading
Further reading on classes and object-oriented programming can be found in the Python documentation.