Methods
We can also add additional methods to our classes. These methods are used either to modify the attributes of the class or to perform actions based on the attributes stored in the class. Finally, we can even use those methods to perform actions on data provided as arguments. In essence, the sky is the limit with methods in classes, so we’ll be able to do just about anything we need to do in these methods.
As with attributes, there are class and instance methods. Class methods have access to their parameters and class attributes, which the access via the syntax class_name.attribute_name. Instance methods by convention have their first parameter as self
and have access to their parameters, class attributes and their instance attributes (self.attribute_name). Class methods are underlined on the UML diagram.
Adding Instance Methods
To add a method to our class, we can simply add a method declaration inside of our class declaration. So, let’s add the methods we need to our Student
class:
class Student:
def __init__(self):
self.name = "name"
self.age = 19
self.student_id = "123456987"
self.credits = 0
self.gpa = 0.0
def birthday(self):
self.age += 1
def grade(self, credits, grade_points):
current_points = round(self.gpa * self.credits)
self.credits += credits
current_points += grade_points
self.gpa = current_points / self.credits
The birthday()
method is pretty straightforward. When that method is called, we simply increase the age of this student by 1 year. However, since this an instance method, we need to add a parameter to the function at the very beginning of our list of parameters, typically named self
. This parameter is automatically added by Python whenever we call an instance method, and it is a reference to the current instance on which the method is being called. We’ll learn more about this later.
Therefore, instead of referencing the age
variable directly, we are using self.age
to access the attribute age
in the current instance of the class. Whenever we want to access an attribute of an instance in the definition of a class, we must use the variable self
(or whatever is the first argument of the method) and a dot in front of it; otherwise, Python may complain that the attribute is not defined or behave in unexpected ways.
The grade()
method is a bit more complex. As parameters, it accepts a reference to the current instance named self
, a number of credits, and the grade points earned for a class; it then must update the credits
and gpa
attributes based on that new information. To do this, it must first calculate the current number of grade points the student has earned based on the current GPA, then update those values and recalculate the GPA.
So, in short, whenever we create an instance method while defining a class in Python, we’ll always need to remember to add an extra parameter—conventionally named self
—to the beginning of our list of parameters so that we can always have a reference to the current instance of the class.
Note, no argument is passed for the self
parameter when calling an instance method. To add a grade to the Student object Bob
, the syntax for calling grade()
is Bob.grade(3, 9)
.
Adding Class methods
Let’s add some class methods. In the class Main
, we note that it has a class-attribute students
which is a list of Student
objects. We’ll add a main
method, create a student and add it to the list of students.
from Student import *
class Main:
students = []
teachers = []
@classmethod
def main(cls, args):
student1 = Student()
cls.students.append(student1)
# change name
cls.students[0].name = "Mari"
print(cls.students[0].name)
#cls.students - a list of student-objects
#cls.students[0] - a student-object stored at index 0
#cls.students[0].name - the name attribute of a student-object stored at index 0
Here we create a student-object, add it to the class-list of students by using cls.students
, then change its name.
We’ve already discussed variable scope earlier in this course. Recall that two different functions may use the same local variable names without affecting each other because they are in different scopes.
The same applies to classes. A class may have an attribute named age
, but a method inside of the class may also use a local variable named age
. Therefore, we must be careful to make sure that we access the correct variable, using the self
reference if we intend to access the attribute’s value in the current instance. Here’s a short example:
class Test:
age = 15
def foo(self):
age = 12
print(age) # 12
print(self.age) # 15
def bar(self):
print(self.age) # 15
print(age) # NameError
As we can see, in the method foo()
we must be careful to use self.age
to refer to the attribute, since there is another variable named age
declared in that method. However, in the method bar()
we see that age
itself causes a NameError
since there is no other variable named age
defined in that scope. We have to use self.age
to reference the attribute.
So, we should always get in the habit of using self
to refer to any attributes, just to avoid any unintended problems later on.
Let’s go ahead and add the promotion()
method to the Teacher
class as well. That method should accept a single integer as a parameter (along with a parameter named self
as the first parameter, of course), and then add that value to the Teacher’s current salary.
Use the first test below to check that we’ve included the correct methods in the Student
and Teacher
classes and main
in Main
. Then, use the second test to confirm that those methods work correctly. Each test below is worth 5 points in this module, for a total of 10 points.