Nein, PEP 412 tut nicht machen __slots__
redundant.
Erstens hat Armin Rigo Recht, dass Sie es nicht richtig messen. Was Sie messen müssen, ist die Größe des Objekts plus die Werte plus die __dict__
selbst (nur für NoSlots
) und die Schlüssel (nur für NoSlots
).
Oder Sie könnten das tun, was er vorschlägt:
cls = Slots if len(sys.argv) > 1 else NoSlots
def f():
tracemalloc.start()
objs = [cls() for _ in range(100000)]
print(tracemalloc.get_traced_memory())
f()
Wenn ich dies auf 64-Bit CPython 3.4 unter OS X laufen, bekomme ich 8824968
für NoSlots
und 25624872
für Slots
. Es sieht also so aus, als ob eine NoSlots
Instanz 88 Bytes benötigt, während eine Slots
Instanz 256 Bytes benötigt.
Wie ist das möglich?
Da gibt es immer noch zwei Unterschiede zwischen __slots__
und einem Schlüssel-Split __dict__
.
Erstens werden die Hashtabellen, die von Wörterbüchern verwendet werden, unter 2/3 voll und sie wachsen exponentiell und haben eine minimale Größe, so dass Sie etwas mehr Platz haben. Und es ist nicht schwer herauszufinden, wie viel Platz man braucht, wenn man sich die gut kommentierte source anschaut: Sie werden 8 Hash-Buckets anstelle von 5 Slots-Zeigern haben.
Zweitens ist das Wörterbuch selbst nicht frei; Es hat einen Standard-Objektkopf, eine Anzahl und zwei Zeiger.Das klingt vielleicht nicht nach viel, aber wenn Sie über ein Objekt sprechen, das nur ein paar Attribute hat (beachten Sie, dass die meisten Objekte nur ein paar Attribute haben ...), kann der dict-Header so viel Unterschied wie die Hash-Tabelle machen .
Und natürlich in Ihrem Beispiel die Werte, so dass die einzigen Kosten hier das Objekt selbst ist, plus die 5 Slots oder 8 Hash-Buckets und dict-Header, so ist der Unterschied ziemlich dramatisch. Im wirklichen Leben, __slots__
wird selten , dass viel von Vorteil sein.
schließlich feststellen, dass PEP 412 nur behauptet:
Benchmarking zeigt, dass die Speichernutzung von 10% bis 20% für die objektorientierte Programme
darüber, wo Sie denken reduziert Verwenden Sie __slots__
. Entweder sind die Einsparungen so groß, dass die Verwendung von __slots__
lächerlich wäre, oder Sie müssen wirklich die letzten 15% auspressen. Oder Sie erstellen ein ABC oder eine andere Klasse, von der Sie erwarten, dass sie von "what-knows-what" unterklassifiziert wird, und die Unterklassen benötigen möglicherweise die Einsparungen. In diesen Fällen wird die Tatsache, dass Sie die Hälfte des Nutzens ohne __slots__
oder sogar zwei Drittel des Nutzens erhalten, in den wenigsten Fällen ausreichen; Sie müssen immer noch __slots__
verwenden.
Der echte Gewinn ist in den Fällen, in denen es sich nicht lohnt, __slots__
; Sie erhalten einen kleinen Vorteil kostenlos.
(Außerdem gibt es definitiv einige Programmierer, die die Hölle aus __slots__
überbeanspruchen, und vielleicht kann diese Änderung einige von ihnen überzeugen, ihre Energie in Mikro zu investieren, etwas anderes nicht ganz so irrelevant zu optimieren, wenn Sie Glück haben.)
Haben Sie die Unterschiede in realen Situationen schon gemessen? :-) Außerdem kann '__slots__' für seine Nebeneffekte (ab) verwendet werden, wie zum Beispiel die Tatsache, dass willkürliche Attribute hinzugefügt werden. –
Ja, ich kenne das Problem mit __slots__, es war mehr eine akademische Frage als in Bezug auf einen bestimmten Anwendungsfall. Ich habe versucht, ein paar Tests zu machen, aber habe keinen Unterschied zwischen Slots und nicht, in Python 3.3 oder 2.7 gefunden. Aber vielleicht ist mein Test fehlerhaft, also werde ich es auch posten. – aquavitae