Object-Oriented Programming#
Class and Object#
Roughly speaking, a class or a type is a blueprint which you use to create objects. An object is an instance of a class.
A class combines data (represented by attributes) and functions (represented by methods) into a single unit.
from math import sqrt
class Vector():
# custom type for 2d vectors
# class attribute shared by all objects of this class
dim = 2
def __init__(self, input_x, input_y):
# constructor, called when new object is created, Vector(x,y)
# self is the object being created
# .x and .y are object attributes
self.x = input_x
self.y = input_y
def length(self):
# length method, returns length of vector
l = sqrt(self.x**2+self.y**2)
return l
def scale(self, c):
# method that scales the vector by a constant c
# changes the object itself
# no return value, so returns None
self.x = self.x * c
self.y = self.y * c
def __repr__(self):
# string representation of the object
# without this method, it prints the memory address
return f'({self.x},{self.y})'
def add(self, other_vector):
# method that adds another vector to this vector, returns new vector
x_new = self.x + other_vector.x
y_new = self.y + other_vector.y
return Vector(x_new, y_new)
def __add__(self, other_vector):
# special method that overloads the + operator
# without this method, vector + vector would raise an error
x_new = self.x + other_vector.x
y_new = self.y + other_vector.y
return Vector(x_new, y_new)
def normalize(self):
# method that scales the vector to unit length
# can call other methods of the same object
l = self.length()
self.scale(1/l)
v = Vector(3,4)
v.x
print(v.x)
v.normalize()
print(v.length())
print(v)
3
1.0
(0.6000000000000001,0.8)
v = Vector(1,1)
w = Vector(2,3)
# custom add method
p = v.add(w)
print(p)
# this is actually calling the __add__ method
q = v + w
print(q)
(3,4)
(3,4)
Exercise:
Create a class Matrix2, which represents a 2x2 matrix. The class should have the following attributes:
a, b, c, d: Elements of the 2x2 matrix, organized as: $\( \begin{bmatrix} a & b \\ c & d \end{bmatrix} \)$
Methods:
A = Matrix2(a, b, c, d): Constructor that initializes the matrix with the given values.
determinant(): Calculates the determinant of the matrix.
transpose(): Returns a new matrix that is the transpose of the current one.
A+B: Adds two matrices together (element-wise addition).
print(A) should print the matrix in the following format:
| a b |
| c d |
class Matrix:
def __init__(self, a, b, c, d):
# constructor to initialize the elements of the matrix
self.a = a
self.b = b
self.c = c
self.d = d
def determinant(self):
# calculates the determinant of the matrix
return self.a * self.d - self.b * self.c
def transpose(self):
# returns a new matrix that is the transpose of the current one
return Matrix(self.a, self.c, self.b, self.d)
def __add__(self, other):
# adds two matrices element-wise
return Matrix(self.a + other.a, self.b + other.b,
self.c + other.c, self.d + other.d)
def __mul__(self, other):
# performs matrix multiplication
return Matrix(self.a * other.a + self.b * other.c,
self.a * other.b + self.b * other.d,
self.c * other.a + self.d * other.c,
self.c * other.b + self.d * other.d)
def __repr__(self):
# string representation of the matrix
# \n is a newline character
return f"| {self.a} {self.b} |\n| {self.c} {self.d} |"
A = Matrix(1,2,3,4)
print(A)
print(f'det(A) = {A.determinant()}')
B = A.transpose()
print(B)
| 1 2 |
| 3 4 |
det(A) = -2
| 1 3 |
| 2 4 |
C = A + B
print(C)
| 2 5 |
| 5 8 |
Extra, not exam material#
In Python, a Module is a file that contains Python code, such as functions, classes, or variables, which can be reused in other Python programs. For example, math
is a built-in module that contains mathematical functions.
We can also create our own module. We can save the definition of the Vector
class in a separate file called myVector.py
. Then we can reuse the class in other programs by importing the module.
from myVector import Vector
v = Vector(1, 2)
Inheritance: A class can inherit from another class, which means that it gets all the attributes and methods of the parent class. This is useful for code reuse and to create a hierarchy of classes. The child class can override methods of the parent class, or add new methods.
# Parent class
class Animal:
def __init__(self, name):
self.name = name
def sayhello(self):
print(f"{self.name} says hello")
# Child class inheriting from Animal
class Dog(Animal):
def speak(self):
print(f"wof")
# Creating objects of the child classes
dog = Dog("Snoopy")
# It can access the attributes and methods of the parent class
dog.sayhello()
# It also has its own methods
dog.speak()
Snoopy says hello
wof