Also spielte ich mit Python herum, während ich beantwortete diese Frage , und ich habe festgestellt, dass dies nicht gilt:
%Vor% aufgrund eines AttributeError: 'object' object has no attribute 'attr'
. Bei jeder Klasse, die vom Objekt geerbt wird, ist es jedoch gültig:
Drucken s.attr
zeigt 'Hallo' wie erwartet an. Warum ist das der Fall? Was in der Python-Sprachspezifikation gibt an, dass Sie Vanilla-Objekten keine Attribute zuweisen können?
Um die Zuweisung beliebiger Attribute zu unterstützen, benötigt ein Objekt ein __dict__
: ein dem Objekt zugeordnetes dict, in dem beliebige Attribute gespeichert werden können. Andernfalls können Sie keine neuen Attribute > hinzufügen.
Eine Instanz von object
enthält nicht eine __dict__
- wenn ja, vor dem schrecklichen zirkulären Abhängigkeitsproblem (da dict
, wie fast alles andere, von% erbt) co_de% ;-), das würde jedes Objekt in Python mit einem dict satteln, was einen Overhead von vielen Bytes pro Objekt bedeuten würde, das momentan kein a benötigt oder benötigt dict (im Prinzip haben alle Objekte, die keine willkürlich zuweisbaren Attribute haben, kein Diktat).
Verwenden Sie zum Beispiel das ausgezeichnete Projekt object
(Sie können es über svn von hier beziehen) ), können wir einige Messungen machen ...:
Sie möchten nicht, dass jedes pympler
144 Byte anstatt nur 16 Byte aufnimmt, oder? -)
Wenn Sie nun eine Klasse erstellen (von was auch immer), ändern sich die Dinge ...:
%Vor% ... das int
ist jetzt hinzugefügt (plus ein bisschen mehr Overhead) - also kann eine __dict__
Instanz beliebige Attribute haben, aber Sie bezahlen dafür ziemlich viel Platz Flexibilität.
Was wäre, wenn Sie dint
s mit nur einem zusätzlichen Attribut int
... möchten? Es ist eine seltene Notwendigkeit, aber Python bietet einen speziellen Mechanismus für den Zweck ...
... nicht ganz so klein wie ein foobar
, wohlgemerkt! (oder auch die zwei int
s, eine die int
und eine self
- die zweite kann neu zugewiesen werden), aber sicherlich viel besser als ein self.foobar
.
Wenn die Klasse das spezielle Attribut dint
(eine Folge von Strings) hat, dann stattet die __slots__
-Anweisung (genauer gesagt, die Standardmetaklasse, class
) jede Instanz mit nicht aus von dieser Klasse mit einem type
(und daher die Fähigkeit, beliebige Attribute zu haben), nur eine endliche, starre Menge von "Slots" (im Grunde Orte, die jeweils einen Verweis auf ein Objekt enthalten können) mit den gegebenen Namen.
Im Gegenzug für die verlorene Flexibilität, erhalten Sie eine Menge Bytes pro Instanz (wahrscheinlich nur sinnvoll, wenn Sie zig Instanzen von Instanzen herumliegen haben, aber sind Anwendungsfälle dafür).
Wie andere Beantworter gesagt haben, hat object
kein __dict__
. object
ist die Basisklasse der all -Typen, einschließlich int
oder str
. Was auch immer von object
bereitgestellt wird, ist für sie ebenfalls eine Belastung. Selbst etwas so einfaches wie ein optionales __dict__
würde für jeden Wert einen zusätzlichen Zeiger benötigen; dies würde zusätzliche 4-8 Bytes Speicher für jedes Objekt in dem System verschwenden, für einen sehr begrenzten Nutzen.
Statt eine Instanz einer Dummy-Klasse in Python 3.3+ zu erstellen, können (und sollten) Sie types.SimpleNamespace
dafür.
Es liegt einfach an der Optimierung.
Dicts sind relativ groß.
%Vor%Die meisten (vielleicht alle) Klassen, die in C definiert sind, haben kein Diktat für die Optimierung.
Wenn Sie sich den Quellcode ansehen Sie werden sehen, dass es viele Überprüfungen gibt, um zu sehen, ob das Objekt ein Diktat hat oder nicht.
Als ich meine eigene Frage untersuchte, entdeckte ich dies über die Python-Sprache: Sie können Dinge wie int erben, und Sie sehen das gleiche Verhalten:
%Vor% Ich nehme an, der Fehler am Ende ist, weil die Funktion add ein int zurückgibt, also müsste ich Funktionen wie __add__
und so überschreiben, um meine benutzerdefinierten Attribute zu behalten. Aber das alles macht jetzt für mich (denke ich) Sinn, wenn ich an "Objekt" wie "int" denke.
Dies ist (IMO) eine der grundlegenden Einschränkungen bei Python - Sie können Klassen nicht wieder öffnen. Ich glaube, dass das eigentliche Problem durch die Tatsache verursacht wird, dass Klassen, die in C implementiert sind, nicht zur Laufzeit geändert werden können ... Unterklassen können, aber nicht die Basisklassen.
Tags und Links python attributes language-design