Attribute der Objektklasse können nicht festgelegt werden

65

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:

%Vor%

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?

    
Smashery 07.10.2009, 01:07
quelle

6 Antworten

108

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 ...:

%Vor%

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 ...

%Vor%

... 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).

    
Alex Martelli 07.10.2009, 01:47
quelle
16

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.

    
Antti Haapala 09.04.2014 15:09
quelle
5

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.

    
Unknown 07.10.2009 02:45
quelle
1

Das liegt daran, dass das Objekt ein "Typ" ist, keine Klasse. Im Allgemeinen erlauben alle Klassen, die in C-Erweiterungen definiert sind (wie alle eingebauten Datentypen und solche wie numpy Arrays), keine beliebigen Attribute hinzuzufügen.

    
Ryan 07.10.2009 01:16
quelle
1

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.

    
Smashery 07.10.2009 01:16
quelle
-1

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.

    
Peter 07.10.2009 01:12
quelle