The Shared Marks List in the Student Class
The computer science department of a school is writing a Python program to store marks for three sections: A, B and C, with 40, 38 and 35 students respectively. A student writes a class Student with a class attribute marks = [] and an __init__ method that appends each student's mark to self.marks. The class also has a class attribute count = 0, which is incremented inside __init__. The program creates three objects for a quick test: s1 = Student("Anu", 78), s2 = Student("Bala", 85) and s3 = Student("Chitra", 92). The student prints s1.marks, s2.marks and Student.count. Later, another student writes s1.marks = [50] and prints s2.marks. The department expected each student object to keep only its own mark and expected the count to show the number of objects created.
1. Predict the output of the first three print statements and explain why `s1.marks`, `s2.marks` and `s3.marks` show the same list. Refer to class attributes and instance attributes.
Read the worked answer
All three prints of marks show [78, 85, 92], and Student.count prints 3.
marks is defined once in the class body, so it is a class attribute shared by all instances. self.marks.append(...) does not create a new list for each object; it finds the shared list and mutates it. Thus every object sees the same appended elements. count is also a class attribute, incremented as Student.count += 1, so it counts object creation.
2. After `s1.marks = [50]`, predict what `s2.marks` and `s1.marks` will be. Explain the difference between mutating a class attribute and rebinding an instance attribute.
Read the worked answer
After s1.marks = [50], s1.marks is [50], while s2.marks remains [78, 85, 92] (and s3.marks too). Assignment to s1.marks creates a new instance attribute on s1; it does not change the class attribute.
In contrast, append mutated the shared class-level list. This is the difference between rebinding a name and mutating the object it refers to.
3. Rewrite the class so that each object stores its own marks list and the count still tracks the number of objects. Show the corrected `__init__` and explain one advantage of using `Student.count` instead of `self.count` for the counter.
Read the worked answer
Corrected version:
class Student:
count = 0
def __init__(self, name, mark):
self.name = name
self.marks = [mark]
Student.count += 1
Each object now gets its own list. Using Student.count keeps one counter on the class; using self.count += 1 would create an instance attribute and leave Student.count unchanged for other objects. If the intent is a per-object mark, storing self.mark = mark is even simpler.