Your problem boils down to a fundamental misunderstanding about how classes work. A class is just a template (think of a cookie cutter shape). By calling the class you are creating an instance of the class. An instance is to a class what a cookie is to a cookie cutter. The function that tells your class how to make an instance is the __init__ function. So when you call:
x = Classroom()
What happens is the __init__ function is called for Classroom. You may be asking "But I didn't ever write an __init__ function for the class, so how does that work?" Simply put, all classes in python will automatically inherit from the object class even if they don't explicitly code it in, which means they use its methods unless you explicitly override them with your own. object has a very simple __init__ that pretty much doesn't do anything.
Going back to the cookie cutter analogy, in the same way that you can make different flavors of cookie (e.g. chocolate chip, oatmeal, peanut butter) from the same cookie cutter, so too can classes make different instances when you instantiate them with different parameters. Like so (adapted from @Prune's answer):
class Student(object):
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def print_student(self):
print (self.age, self.grade, self.name)
James = Student('James Herbert', 15, 9)
James.print_student()
Diego = Student('Diego Heriberto', 14, 9)
Diego.print_student()
Which should print out:
15 9 James Herbert
14 9 Diego Heriberto
Each instance is different, and so behaves differently, but they both follow the same template laid out by the class.
If you want a Classroom class, you could do something like this:
class Classroom(object):
def __init__(self):
# create a list to hold students and assign the list to self
self.students = list()
def add_student(self, student):
self.students.append(student)
def print_students(self):
# use a loop to print out all the students in the classroom instance
for stud in self.students:
stud.print_student()
cr = Classroom()
James = Student('James Herbert', 15, 9)
Diego = Student('Diego Heriberto', 14, 9)
cr.add_student(James)
cr.add_student(Diego)
cr.print_students()
This would have identical output to what was shown previously.
You may ask yourself "But there is the 'self' parameter that I never pass in. Is Python broken?" Python is working just fine. The self parameter is implicit when you call a method on an instance like James or Diego, but it is explicit in the actual body of the method. If you want to modify the instance in a method, then you must modify the self parameter. That is why we assign values to it in __init__. If you want to find out something about an instance, you check for it on the self parameter.