Dass man Implementierungsdetails verstehen möchte, ist IMHO nicht schlecht. Aber (und das ist oft ein Problem) muss man es auch (und sogar noch viel mehr) können, Sachen zu benutzen,
ohne genau zu wissen, wie es implementiert ist.
Python ist, wie quasi jede andere Sprache auch, eine
mathematische Beschreibung von einem Programm, nicht eine physikalische. Es wird beschrieben,
was gemacht werden soll, nicht
wie.
Nur um das mal am Beispiel `datetime.datetime` zu verdeutlichen:
Die Dokumentation beschreibt, was man mit `datetime`-Objekten machen kann. Z. B. kann man neue Objekte erstellen (`datetime.now()` etc.), man kann ihr Jahr, Monat, Tag, etc. abfragen (aber nicht ändern), man kann sie vergleichen und mit `timedelta`-Objekten verrechnen, etc.
An keiner Stelle wird geschrieben,
wie ein `datetime`-Objekt implementiert ist. Weil das in erster Linie nicht wichtig ist, weil man ja sinnvolle Sachen mit `datetime`-Objekten machen will und
nicht Elektronen dabei zugucken will, wie sie sich in einer CPU bewegen.
Wenn man jetzt wissen will,
wie ein `datetime`-Objekt „intern“ funktioniert, muss man sich erstmal eine Implementierung von Python aussuchen, bei der man sich das angucken will. Weil ja gerade nicht festgelegt ist,
wie ein solches Objekt aufgebaut ist. Und natürlich noch eine spezielle Version der Implementierung, weil sich das ja alles ändern kann.
In der aktuellen Version von CPython
sieht das dann so aus:
Code: Alles auswählen
/* # of bytes for year, month, day, hour, minute, second, and usecond. */
#define _PyDateTime_DATETIME_DATASIZE 10
/* The datetime and time types have hashcodes, and an optional tzinfo member,
* present if and only if hastzinfo is true.
*/
#define _PyTZINFO_HEAD \
PyObject_HEAD \
Py_hash_t hashcode; \
char hastzinfo; /* boolean flag */
#define _PyDateTime_DATETIMEHEAD \
_PyTZINFO_HEAD \
unsigned char data[_PyDateTime_DATETIME_DATASIZE];
typedef struct
{
_PyDateTime_DATETIMEHEAD
unsigned char fold;
PyObject *tzinfo;
} PyDateTime_DateTime; /* hastzinfo true */
Wenn man die Makros halbwegs aufdröselt, hat man also ungefähr das hier:
Code: Alles auswählen
typedef struct
{
PyObject_HEAD
Py_hash_t hashcode;
char hastzinfo; /* boolean flag */
unsigned char data[10];
unsigned char fold;
PyObject *tzinfo;
} PyDateTime_DateTime; /* hastzinfo true */
Wie man sieht, ist ein `datetime`-Objekt ein Python-Objekt (wegen `PyObject_HEAD`), hat einen Hashwert, ein Flag, das sagt, ob es Zeitzoneninformationen hat, 10 Byte an „Daten“, ein Byte, das sagt, ob das erste oder zweite Mal gemeint ist, an dem das Datum war (Stichwort Zeitumstellung) und dann noch ein Zeitzonen-Objekt.
Das Problem an der Sache ist: Das sagt
immer noch nicht, wie so ein Objekt „intern“ funktioniert. Weil das wieder eine Beschreibung in einer Programmiersprache (in diesem Fall C) ist, die wieder nur das
was und nicht das
wie beschreibt (der C-Standard beschreibt das Verhalten von C in Bezug auf eine „abstrakte Maschine“, also ein mathematisches Objekt, und nicht in Bezug auf reale Hardware, die tatsächlich existieren würde). Man müsste sich jetzt also wieder eine spezielle Implementierung von C suchen und sich da angucken, wie `struct`s, Zeiger, Arrays etc. implementiert sind. (Und das geht natürlich nicht allgemein, sondern nur in speziell einem Fall, weil die C-Implementierung jedes einzelne `struct` oder Array (etc.) anders als alle anderen implementieren könnte. Weil das
wie eben nicht genau festgelegt ist, sondern nur,
was das Programm am Ende tun soll, wenn es ausgeführt wird.)
Und das sagt
immer noch nicht,
wie das alles eigentlich™ funktioniert, weil die C-Implementierung ja auch irgendwie implementiert sein muss. Also z. B. als Interpreter (dann sind wir wieder bei Schritt 1, wie ist
der Interpreter aufgebaut) oder als Compiler, der irgendeinen Maschinencode ausspuckt, der dann auf einer realen CPU ausgeführt wird.
Aber halt,
wie läuft das Programm dann auf der CPU? Jedenfalls nicht so, wie der Maschinencode das Programm beschreibt. So war eine CPU vielleicht mal vor 40 Jahren aufgebaut, aber heutzutage wäre das viel zu langsam. Also übersetzt die CPU intern den Maschinencode in eine Form, die schneller ausgeführt werden kann als der eigentliche Maschinencode. Und führt die einzelnen Instruktionen in einer anderen Reihenfolge aus als sie eigentlich im Programm vorkommen. Und Speicherzugriffe? Viel zu langsam, da macht die CPU auch was anderes als eigentlich™ im Programm steht.
Worauf ich hinaus will: Das ist alles ein riesiges Fraktal an Komplexität, das man alles gar nicht verstehen
kann. Weil es einfach alles viel zu viel ist. Abstraktion ist das einzige, was dagegen hilft. Und in diesem Fall ist die Abstraktion halt, dass ein `datetime`-Objekt keine von der Sprache Python festlegbare interne Struktur haben kann, sondern dass man das Objekt so verwendet, wie es in der Doku beschrieben ist. Also z. B. dass `a < b` einen Vergleich macht, ob `a` früher als `b` ist, aber nicht wie. Weil das „wie“ zu beschreiben noch viel komplizierter wäre als das, was ich gerade nur über die Struktur von `datetime`-Objekten geschrieben habe.