Also habe ich bei der Beantwortung dieser Frage mit Python herumgespielt und festgestellt, dass dies nicht gültig ist:
o = object()
o.attr = 'hello'
aufgrund eines AttributeError: 'object' object has no attribute 'attr'
. Bei jeder vom Objekt geerbten Klasse gilt jedoch Folgendes:
class Sub(object):
pass
s = Sub()
s.attr = 'hello'
Beim Drucken s.attr
wird wie erwartet "Hallo" angezeigt. Warum ist das so? Was in der Python-Sprachspezifikation gibt an, dass Sie Vanilleobjekten keine Attribute zuweisen können?
python
attributes
language-design
Smashery
quelle
quelle
object
Typ ist unveränderlich und neue Attribute können nicht hinzugefügt werden? Dies scheint am sinnvollsten zu sein.object
Klasseninstanzen und nicht fürobject
Klassen festzulegen.Antworten:
Um die Zuweisung beliebiger Attribute zu unterstützen, benötigt ein Objekt Folgendes
__dict__
: ein dem Objekt zugeordnetes Diktat, in dem beliebige Attribute gespeichert werden können. Ansonsten gibt es nirgendwo zu setzen neue Attribute.Eine Instanz von
object
trägt nicht ein__dict__
- wenn ja, vor dem schrecklichen Problem der zirkulären Abhängigkeit (dadict
, wie fast alles andere, vonobject
;-) erbt , würde dies jedes Objekt in Python mit einem Diktat satteln , was einen Overhead bedeuten würde von vielen Bytes pro Objekt, die derzeit kein Diktat haben oder benötigen (im Wesentlichen haben oder benötigen alle Objekte, die keine willkürlich zuweisbaren Attribute haben, kein Diktat).Mit dem hervorragenden
pympler
Projekt (das Sie hier über svn erhalten können ) können wir beispielsweise einige Messungen durchführen ...:Sie möchten nicht, dass jeder
int
144 Bytes statt nur 16 Bytes belegt, oder? -)Wenn Sie nun eine Klasse erstellen (von was auch immer erben), ändern sich die Dinge ...:
... das
__dict__
wird jetzt hinzugefügt (plus etwas mehr Overhead) - so kann einedint
Instanz beliebige Attribute haben, aber Sie zahlen ziemlich viel Platz für diese Flexibilität.Was wäre, wenn Sie
int
s mit nur einem zusätzlichen Attribut wolltenfoobar
...? Es ist eine seltene Notwendigkeit, aber Python bietet einen speziellen Mechanismus für diesen Zweck ...... nicht ganz so klein wie ein
int
, wohlgemerkt! (oder sogar die zweiint
s, eins dasself
und eins dasself.foobar
- das zweite kann neu zugewiesen werden), aber sicherlich viel besser als adint
.Wenn die Klasse das
__slots__
spezielle Attribut (eine Folge von Zeichenfolgen) hat, rüstet dieclass
Anweisung (genauer gesagt die Standard-Metaklassetype
) nicht jede Instanz dieser Klasse mit einem__dict__
(und daher der Fähigkeit, beliebige Attribute zu haben) aus, sondern nur mit einem Endlichen , starrer Satz von "Schlitzen" (im Grunde Orte, die jeweils einen Verweis auf ein Objekt enthalten können) mit den angegebenen Namen.Als Gegenleistung für die verlorene Flexibilität erhalten Sie eine Menge Bytes pro Instanz (wahrscheinlich nur dann sinnvoll, wenn Sie zig Instanzen haben, die herum galoppieren, aber es gibt Anwendungsfälle dafür).
quelle
__slots__
nicht Arbeit mit variabler Länge Typen wiestr
,tuple
und in Python 3 auchint
.__dict__
, muss seine Klasse ein__slot__
Attribut haben?Sub
das__dict__
Attribut und das Objekt nicht haben, da es soSub
erbtobject
, wie dieses Attribut (und andere wie__module__
) in der Vererbung hinzugefügt werden? Vielleicht könnte dies eine neue Frage sein__dict__
wird nur beim ersten Mal erstellt, wenn es benötigt wird. Daher ist die Speicherkostensituation nicht ganz so einfach, wie es dieasizeof
Ausgabe aussehen lässt. (asizeof
weiß nicht, wie man__dict__
Materialisierung vermeidet .) Sie können sehen, dass das Diktat erst materialisiert wird, wenn es in diesem Beispiel benötigt wird , und Sie können hier einen der Codepfade sehen, die für die__dict__
Materialisierung verantwortlich sind .Wie andere Antwortende gesagt haben, hat ein
object
kein__dict__
.object
ist die Basisklasse aller Typen, einschließlichint
oderstr
. Was auch immer von bereitgestellt wird,object
wird auch für sie eine Belastung sein. Selbst etwas so Einfaches wie ein Optionales__dict__
würde einen zusätzlichen Zeiger für jeden Wert benötigen. Dies würde zusätzliche 4-8 Bytes Speicher für jedes Objekt im System verschwenden, was für einen sehr begrenzten Nutzen von Bedeutung ist.Anstatt eine Instanz einer Dummy-Klasse zu erstellen, können (und sollten) Sie in Python 3.3+
types.SimpleNamespace
dies verwenden.quelle
Es liegt einfach an der Optimierung.
Diktate sind relativ groß.
Die meisten (möglicherweise alle) Klassen, die in C definiert sind, haben kein Optimierungsdiktat.
Wenn Sie sich den Quellcode ansehen, werden Sie feststellen, dass es viele Überprüfungen gibt, um festzustellen, ob das Objekt ein Diktat hat oder nicht.
quelle
Als ich meine eigene Frage untersuchte, entdeckte ich Folgendes über die Python-Sprache: Sie können von Dingen wie int erben, und Sie sehen dasselbe Verhalten:
Ich gehe davon aus, dass der Fehler am Ende darin besteht, dass die Funktion add ein int zurückgibt. Daher müsste ich Funktionen wie
__add__
und so überschreiben , um meine benutzerdefinierten Attribute beizubehalten. Aber das alles macht jetzt Sinn für mich (denke ich), wenn ich an "Objekt" wie "int" denke.quelle
Das liegt daran, dass das Objekt ein "Typ" ist, keine Klasse. Im Allgemeinen erlauben alle Klassen, die in C-Erweiterungen definiert sind (wie alle integrierten Datentypen und solche wie Numpy-Arrays), das Hinzufügen beliebiger Attribute nicht.
quelle
__dict__
Aus den von Alex Martelli angegebenen Gründen können Sie den Klassen, die keine haben , jedoch immer noch keine Attribute hinzufügen .https://docs.python.org/3/library/functions.html#object :
quelle
Dies ist (IMO) eine der grundlegenden Einschränkungen bei Python - Sie können Klassen nicht erneut öffnen. Ich glaube jedoch, dass das eigentliche Problem durch die Tatsache verursacht wird, dass in C implementierte Klassen zur Laufzeit nicht geändert werden können ... Unterklassen können, aber nicht die Basisklassen.
quelle