Trouble understanding classes in python
I am a beginner in python and I am having trouble understanding classes. I have a task that requires me to create a class that should return a students information e.g. name, id, age and marks. I have made a class but am having trouble with the output and keep on getting an attribute error:
print("Student: " + self.name + " ID: " + self.ID + " Age: " + self.age + " Mark: " + self.mark)
AttributeError: 'Student' object has no attribute 'age'
I was wondering if someone could explain what I am doing wrong here as I am quite lost.
Rest of the code:
import random
class Student:
def __init__(self, name, ID):
self.name = name
self.ID = ID
def setAge(self, age):
self.age = age
self.age = random.randint(0, 100)
def setMarks(self, marks):
self.marks = marks
self.marks = random.randint(0, 100)
def Display(self):
print("Student: " + self.name + " ID: " + self.ID + " Age: " + self.age + " Mark: " + self.mark)
student = Student("John", "ID123")
student.Display()
You didn't call student.setMarks()
and student.setAge()
, so marks
and age
attributes are not created in object yet.
The solution is to call these two methods before calling student.Display()
In your example, you try to access the variable, before the assignment. You would actually have to call student.setAge
and student.setMarks
with arguments.
On the other note, in your function setAge you instantly overwrite the value, so consider removing either first or second assignment:
def setAge(self, age):
self.age = age # first assignment
self.age = random.randint(0, 100) # second assignment
Python objects are a container that has attributes you can set. If you don't set an attribute but try to read it, you get an AttributeError
, meaning that the attribute you are looking for does not exist.
Currently, student = Student(...)
calls Student.__init__
, which assigns the name
and ID
attribute of the object. You never call student.setAge
or student.setMarks
, so your object's age
and marks
attributes are never set and can not be accessed.
It is traditional to assign default values in the __init__
method if you want to generally avoid unexpected crashes like that.
Another thing is that rather having getter and setter methods, as Java would, for example, Python encourages the use of properties. Properties are objects in the class template that can be accessed like a normal attribute, but allow you to run arbitrary code in place of the access and assignment operators.
Putting all that together, you could write something like
class Student:
def __init__(self, name, ID, age=None, marks=None):
self.name = name
self.ID = ID
self.age = random.randint(0, 100) if age is None else age
self.marks = random.randint(0, 100) if marks is None else marks
@property
def marks(self):
return self._marks
@marks.setter
def marks(self, value):
# Example of a check you could do
if not isinstance(value, int):
raise TypeError('Marks must be an integer')