Classes#
Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state. (https://docs.python.org/3/tutorial/classes.html)
Create new class for describing students:
class Student():
"""Represents a student in a university database."""
name = 'noName'
Create a new student <-> create new instance of the Student class:
theStudent = Student()
print( theStudent )
<__main__.Student object at 0x7f796c137770>
Access class data:
print( theStudent.name )
noName
Edit class data:
theStudent.name = 'Anna'
print( theStudent.name )
Anna
__init__ Function#
class Student():
"""Represents a student."""
# name = 'noName'
# specialization = "noSpecialization"
def __init__(self, name='noName', specialization='noSpecialization'):
"""Initialize the Student object with the student's name and specialization."""
self.name = name
self.specialization = specialization
theStudent = Student('Anna','Chemistry')
print( theStudent )
print( theStudent.name )
print( theStudent.specialization )
<__main__.Student object at 0x7f796c1374d0>
Anna
Chemistry
?Student.__init__
theSecondStudent = Student('Robert', 'physics')
print( theSecondStudent )
print( theSecondStudent.name )
print( theSecondStudent.specialization )
<__main__.Student object at 0x7f796c3a2350>
Robert
physics
Add functionalities to the class:
class Student():
"""Represents a student."""
#name = 'noName'
#passed_courses = []
def __init__(self, name='noName',passed_courses=None):
"""Initialize the Student class with the student's name."""
self.name = name
self.passed_courses = passed_courses if passed_courses is not None else []
def addCourse(self, course):
"""Add a course to the list of passed courses."""
self.passed_courses.append(course)
theStudent = Student('Joost')
print( theStudent.passed_courses)
theStudent.addCourse('Programming 1')
#theStudent.addCourse( 'Programming 2', 'Quantum Mechanics 1' )
print( theStudent.passed_courses)
[]
['Programming 1']
class Student():
"""Represents a student."""
name = 'noName'
passed_courses = []
def __init__(self, name='noName',passed_courses=passed_courses):
"""Initialize the Student class with the student's name."""
self.name = name
self.passed_courses = passed_courses
def addCourse(self, course):
"""Add a course to the list of passed courses."""
self.passed_courses.append(course)
theStudent = Student('Joost')
print( theStudent.passed_courses)
theStudent.addCourse('Programming 1')
#theStudent.addCourse( 'Programming 2', 'Quantum Mechanics 1' )
print( theStudent.passed_courses)
[]
['Programming 1']
Warning
But be careful! Try to define default value of passed_courses outside of init and see what happens:
newStudent = Student('Emily')
#print(theStudent.passed_courses)
#theStudent.addCourse('Analytical mechanics')
print(newStudent.name )
print(newStudent.passed_courses )
Emily
['Programming 1']
Add functionalities to the class:
class Student():
"""Represents a student."""
#name = 'noName'
def __init__(self, name='noName'):
"""Initialize the student class with the student's name."""
self.name = name
self.passed_courses = [] # initially should be empty
def addCourse(self, course):
"""Add a trick to the list of tricks."""
self.passed_courses.append(course)
theStudent = Student('Andrea')
theStudent.addCourse('Quantum mechanics')
theStudent.addCourse('Electrodynamics')
anotherStudent = Student('Mary')
anotherStudent.addCourse('Neuroscience')
print( theStudent.name )
print( theStudent.passed_courses )
print( anotherStudent.name )
print( anotherStudent.passed_courses )
Andrea
['Quantum mechanics', 'Electrodynamics']
Mary
['Neuroscience']
class Student():
"""Represents a student."""
#name = 'noName'
def __init__(self, name='noName'):
"""Initialize the student class with the student's name and a list of passed courses."""
self.name = name
self.passed_courses = [] # initially tricks should be empty
def addCourse(self, course):
"""Add a trick to the list of tricks."""
self.passed_courses.append( course )
def works(self):
"""Let the student work."""
print(self.name+' submits and assignment')
Lucy = Student('Lucy')
Lucy.works()
print(Lucy)
Lucy submits and assignment
<__main__.Student object at 0x7f796c1374d0>
Magic Methods#
Python classes come with many predefined magic methods which are automatically called in certain situations.
__init__(self, ...)is such a magic method which is automatically called upon initialization of the class instance.
There are many, many other magic methods automatically called upon:
construction and initialization
comparisons ( What should
oneStudent == anotherStudentmean?)applications of mathematical operations ( What should
oneStudent + anotherStudentmean?)…
See https://rszalski.github.io/magicmethods for a full list.
Use __str__ (magic method) to define a simple string which is used within the print(...) command:
class Student():
"""Represents a student."""
#name = 'noName'
def __init__(self, name='noName'):
"""Creates the student object with the student's name."""
self.name = name
def work(self):
"""Let the student work."""
print(self.name+' submits an assignment')
def __str__(self):
"""Create a string describing the class and return it."""
return 'I\'m a student and my name is ' + self.name
Lars = Student('Lars')
print( Lars )
#Bailey.bark()
I'm a student and my name is Lars
Classes: Mathematical example#
Let us define a class which describes square diagonal matrices of the form
and which implements addition and substraction operations.
class diagMatrix():
"""Represent diagonal matrices."""
def __init__(self, value, dim):
"""Initialize the diagonal matrix.
Keyword arguments:
value -- diagonal values
dim -- dimension of the matrix
"""
# sanity checks
assert type(value) in [int, float], "value must be a number."
assert isinstance(dim, int), "dim must be an integer."
self.value = value
self.dim = dim
def __str__(self):
"""Create and return a simple ASCII reprensentation of the diagonal matrix."""
myStr = ''
for n in range(0, self.dim):
for m in range(0, self.dim):
if(n == m):
myStr += str(self.value) + ' '
else:
myStr += '0 '
myStr += '\n'
return myStr
diagMatrixA = diagMatrix(value=-2, dim=13)
print( diagMatrixA )
-2 0 0 0 0 0 0 0 0 0 0 0 0
0 -2 0 0 0 0 0 0 0 0 0 0 0
0 0 -2 0 0 0 0 0 0 0 0 0 0
0 0 0 -2 0 0 0 0 0 0 0 0 0
0 0 0 0 -2 0 0 0 0 0 0 0 0
0 0 0 0 0 -2 0 0 0 0 0 0 0
0 0 0 0 0 0 -2 0 0 0 0 0 0
0 0 0 0 0 0 0 -2 0 0 0 0 0
0 0 0 0 0 0 0 0 -2 0 0 0 0
0 0 0 0 0 0 0 0 0 -2 0 0 0
0 0 0 0 0 0 0 0 0 0 -2 0 0
0 0 0 0 0 0 0 0 0 0 0 -2 0
0 0 0 0 0 0 0 0 0 0 0 0 -2
diagMatrixA = diagMatrix(-4.2, 3)
print( diagMatrixA )
-4.2 0 0
0 -4.2 0
0 0 -4.2
diagMatrixA = diagMatrix("string", 3)
print( diagMatrixA )
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[16], line 1
----> 1 diagMatrixA = diagMatrix("string", 3)
2 print( diagMatrixA )
Cell In[14], line 13, in diagMatrix.__init__(self, value, dim)
5 """Initialize the diagonal matrix.
6
7 Keyword arguments:
8 value -- diagonal values
9 dim -- dimension of the matrix
10 """
12 # sanity checks
---> 13 assert type(value) in [int, float], "value must be a number."
14 assert isinstance(dim, int), "dim must be an integer."
16 self.value = value
AssertionError: value must be a number.
diagMatrixA = diagMatrix(4, 3.2)
print( diagMatrixA )
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
Cell In[22], line 1
----> 1 diagMatrixA = diagMatrix(4, 3.2)
2 print( diagMatrixA )
Cell In[20], line 14, in diagMatrix.__init__(self, value, dim)
12 # sanity checks
13 assert type(value) in [int, float], "value must be a number."
---> 14 assert isinstance(dim, int), "dim must be an integer."
16 self.value = value
17 self.dim = dim
AssertionError: dim must be an integer.
diagMatrixA = diagMatrix(4, 3)
print( diagMatrixA )
diagMatrixB = diagMatrix(2, 3)
print( diagMatrixB )
4 0 0
0 4 0
0 0 4
2 0 0
0 2 0
0 0 2
diagMatrixB = diagMatrixA + diagMatrixB
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[22], line 1
----> 1 diagMatrixB = diagMatrixA + diagMatrixB
TypeError: unsupported operand type(s) for +: 'diagMatrix' and 'diagMatrix'
Implement diagMatrixA + diagMatrixB via __add__(self, other).
class diagMatrix(diagMatrix):
def __add__(self, other):
"""Add two diagonal matrices.
Keyword arguments:
self -- first diagonal matrix
other -- second diagonal matrix
"""
# sanity checks
assert self.dim == other.dim, "Matrices have different dimensions."
newValue = self.value + other.value
newDim = self.dim
return diagMatrix(newValue, newDim)
diagMatrixA = diagMatrix(4, 3)
print( diagMatrixA )
diagMatrixB = diagMatrix(2, 3)
print( diagMatrixB )
diagMatrixC = diagMatrixA - diagMatrixB
print(diagMatrixC)
4 0 0
0 4 0
0 0 4
2 0 0
0 2 0
0 0 2
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[6], line 25
22 diagMatrixB = diagMatrix(2, 3)
23 print( diagMatrixB )
---> 25 diagMatrixC = diagMatrixA - diagMatrixB
27 print(diagMatrixC)
TypeError: unsupported operand type(s) for -: 'diagMatrix' and 'diagMatrix'
Note
Note the diagMatrix(diagMatrix) syntax. This is called inheritance: The new class diagMatrix(...) inherits the properties and methods from the “parent” class ...(diagMatrix) in the brackets.
class diagMatrix(diagMatrix):
def __sub__(self, other):
"""Subtract two diagonal matrices.
Keyword arguments:
self -- first diagonal matrix
other -- second diagonal matrix
"""
# sanity checks
assert self.dim == other.dim, "Matrices have different dimensions."
newValue = self.value - other.value
newDim = self.dim
return diagMatrix(newValue, newDim)
diagMatrixC = diagMatrix(5, 4)
print( diagMatrixC )
diagMatrixD = diagMatrix(3, 4)
print( diagMatrixD )
5 0 0 0
0 5 0 0
0 0 5 0
0 0 0 5
3 0 0 0
0 3 0 0
0 0 3 0
0 0 0 3
print(diagMatrixC + diagMatrixD)
8 0 0 0
0 8 0 0
0 0 8 0
0 0 0 8
Warning
diagMatrixA and diagMatrixB do not know about __sub__.
print(diagMatrixA - diagMatrixB)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[10], line 1
----> 1 print(diagMatrixA - diagMatrixB)
TypeError: unsupported operand type(s) for -: 'diagMatrix' and 'diagMatrix'