Zunächst einmal ist self ein konventioneller Name, den du durch irgendetwas anderes ersetzen könntest (logischerweise).
Es bezieht sich auf das Objekt selbst, also wenn du es verwendest, erklärst du, dass .name und .age Eigenschaften der Studentenobjekte (nicht der Studentenklasse) sind, die du erstellen wirst.
class Student:
#wird jedes Mal aufgerufen, wenn du eine neue Studenteninstanz erstellst
def __init__(self,name,age): #spezielle Methode zur Initialisierung
self.name=name
self.age=age
def __str__(self): #spezielle Methode, die beispielsweise aufgerufen wird, wenn du print verwendest
return "Student %s ist %s Jahre alt" %(self.name,self.age)
def call(self, msg): #albernes Beispiel für benutzerdefinierte Methode
return ("Hey, %s! "+msg) %self.name
#Initialisierung zweier Instanzen der Studentenklasse
bob=Student("Bob",20)
alice=Student("Alice",19)
#Anwendung
print bob.name
print bob.age
print alice #das funktioniert nur, wenn du die __str__ Methode definierst
print alice.call("Komm her!") #beachte, dass du keinen Wert für self angibst
#du kannst Attribute ändern, zum Beispiel wenn Alice älter wird
alice.age=20
print alice
Der Code ist hier zu finden