Python ist 10 Jahre jünger als Smalltalk, von dem AFAIK self kommt. Dort ist es implizit, muss also nicht in der Parameterliste einer Methode aufgeführt werden. Allerdings gibt es in Smalltalk auch nur Methoden, keine Funktionen.
In Smalltalk gibt es auch keine Attribute, sodass man weiß, dass `foo bar` immer ein Aufruf der Methode `bar` in dem Objekt, welches in der Variablen `foo` steckt bedeutet. Smalltalk hat es nicht nötig, Name der Methode (auch Selektor genannt) und Variable mit einem Punkt aneinanderzuketten. Man kann auch nicht "von außen" auf Exemplarvariablen zugreifen, was dann zu folgendem Boilerplate-Code in der Klasse `Foo`, die eine Exemplarvariable `bar` haben möge, führt:
Das `^` ist der Return-Operator. Fehlt er, wird implizit `^self` ergänzt.
In Python gab es AFAIK zuerst Funktionen. Dann hat sich GvR überlegt, wie er mit dem, was er hatte, jetzt Objektorientierung einführen konnte und erkannt, dass das eigentlich nur ein paar Konventionen sind. `foo.bar()` ist eine Abkürzung für `foo_bar(foo)`, wobei jetzt `foo_bar` geeignet gewählt werden muss. Man stecke diese Funktion also in ein neues Objekt, das man Klasse nennt und schreibt dann `Foo.bar`. Will ich jetzt `bar` definieren, brauche ich einen Namen für den ersten (und in meinem Beispiel einzigen) Parameter und da fiel ihm wohl `self` als Konvention ein. Netter Nebeneffekt ist, dass `Foo.bar` eine (fast) ganz normale Funktion ist.
In Smalltalk kommt man normalerweise mit Methodenobjekten nicht direkt in Kontakt. Man kann zwar `Foo compiledMethodAt: #bar` benutzen, aber das ist bereits Metaprogrammierung und nicht mehr Teil des Sprachkerns. Auch müsste man selbst die Suche in Oberklassen durchführen.
Zwischen Smalltalk und Python lag noch die Sprache Self, die z.B. Vorbild für JavaScript war. Man hat hier versucht, die Smalltalk-Essenz zu finden und dabei Klassen als entbehrlich erkannt.
Self hat Objekte mit Slots, in denen (neben normalen Objekten) Methoden stecken können. Variablen irgendeiner Art gibt es keine. Auch keine Kontrollstrukturen oder andere Syntax außer `^`, welches jedoch nur noch ein nicht-lokales-Return in Blöcken ist. Ein Objekt `foo: (| bar. |)` hat einen Slot namens bar, den man mit `foo bar` abfragen und mit `foo bar: 1` setzen kann. `bar` und `bar:` sind nicht mehr wie in Smalltalk explizit zu schreibende Zugriffsfunktionen sondern primitive Slotzugriffe und damit eher mit Python-Attributen zu vergleichen. Im Gegensatz zu Python kann man sie aber nicht überschreiben. Will eine Methode `baz` des Objekts `foo` auf `bar` zugreifen, muss man (das implizit gebundene) `self` benutzen: `(| bar. baz = (self bar + 1) |)`. Würde man in der Methode nur `bar` benutzen, wäre es wie eine lokale Variable, nämlich ein Slot des aktiven Kontextobjekts, den man in jeder Methode mit dem leeren Empfänger (bei `foo bar` ist `foo` der Empfänger der Nachricht `bar`) ansprechen kann.
Das ist herrlich einfach und dennoch mächtig und extrem objektorientiert. So hätte man's in Python auch regeln können.
Dort hat man sich aber stattdessen dafür entschieden, lieber alles als Funktionen zu sehen und Objekte und Methoden als Speziallfall davon anzusehen. Ein bisschen so wie bei Lisp, wo objektorientierte Erweiterungen traditionell generische Funktionen sind, die über alle ihre Argumente zur richtigen Multimethode dispatchen. Betrachtet man nur das erste (explizite) Argument, dann funktioniert es so wie bei Python.
Stefan