Der entscheidende konzeptionelle Unterschied zwischen deinen Funktionen und den Funktionen in deiner Klasse ist, dass letztere keine Funktionen, sondern Methoden sind. Das heisst es ist Code der nur ausgefuehrt werden kann zusammen mit einer Instanz der dazugehoerigen Klasse. In Python wird das explizit verdeutlicht durch den ersten Parameter self (der auch pillepalle heissen koennte, aber die Konvention, von der man auch nicht abweichen sollte, ist halt self).
Und das ist auch sinnvoll so: eine Funktion zum oeffnen einen Tuer eines Autos muss wissen, auf welches Auto sich die Tueroeffnung beziehen soll.
Ein weiteres Puzzleteil ist die Frage, wann die Zeile "def f2(self...)" denn ausgefuehrt wird. Die darin angegebenen Namen sind entweder positionale Argumente (muessen also auch immer uebergeben werden beim Aufruf), oder benannte Argumente mit einem Standardwert. Und bei letzteren haben sich die Urvaeter von Python dafuer entschieden, dass diese Standardwerte *bei Definition* und nicht erst bei einem spaeteren Aufruf ausgewertet werden. Also nur einmal statt viele male. Das ist halt so (auch mit gutem Grund, aber das fuehrt zu weit).
Damit kannst du dich aber in dieser Zeile nicht auf self beziehen: das existiert ja erst, wenn du
machst. Und wenn du self weglaesst, dann rufst du f auf, aber f ist eine Methode, und zu dem Zeitpunkt hast du genauso wenig eine Instanz.
was du tun kannst, ist folgendes (nur der relevante Teil dargestellt):