Aby obsłużyć przypisanie dowolnego atrybutu, obiekt potrzebuje a __dict__
: dict skojarzonego z obiektem, w którym można przechowywać dowolne atrybuty. W przeciwnym razie nie ma gdzie umieścić nowych atrybutów.
Instancja object
ma nie nosić ze sobą __dict__
- gdyby tak się stało, przed strasznym okrągłym problemu uzależnienia (ponieważ dict
, jak większość wszystko inne, dziedziczy od object
;-) byłoby to siodło każdy obiekt w Pythonie z dict, co oznaczałoby obciążenie z wielu bajtów na obiekt, który obecnie nie ma lub nie potrzebuje dyktowania (zasadniczo wszystkie obiekty, które nie mają przypisywalnych atrybutów, nie mają ani nie potrzebują dyktowania).
Na przykład, korzystając z doskonałego pympler
projektu (możesz go pobrać przez svn stąd ), możemy wykonać kilka pomiarów ...:
>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16
Nie chciałbyś, aby każdy int
zajmował 144 bajty zamiast tylko 16, prawda? -)
Teraz, kiedy tworzysz klasę (dziedzicząc po czymkolwiek), rzeczy się zmieniają ...:
>>> class dint(int): pass
...
>>> asizeof.asizeof(dint(23))
184
... __dict__
jest teraz dodawany (plus trochę więcej narzutu) - więc dint
instancja może mieć dowolne atrybuty, ale za taką elastyczność płacisz sporo miejsca.
A co by było, gdybyś chciał mieć int
tylko jeden dodatkowy atrybut foobar
...? Jest to rzadka potrzeba, ale Python oferuje specjalny mechanizm do tego celu ...
>>> class fint(int):
... __slots__ = 'foobar',
... def __init__(self, x): self.foobar=x+100
...
>>> asizeof.asizeof(fint(23))
80
... nie dość jak mały jako int
, przeszkadza ci! (lub nawet dwa int
s, jeden self
i jeden self.foobar
- drugi można ponownie przypisać), ale z pewnością znacznie lepszy niż dint
.
Gdy klasa ma __slots__
atrybut specjalny (sekwencję ciągów), to class
instrukcja (a dokładniej domyślna metaklasa type
) nie wyposaża każdej instancji tej klasy w __dict__
atrybut (a tym samym możliwość posiadania dowolnych atrybutów), tylko skończoną , sztywny zbiór "szczelin" (w zasadzie miejsc, które mogą zawierać jedno odniesienie do jakiegoś obiektu) o podanych nazwach.
W zamian za utratę elastyczności zyskujesz dużo bajtów na instancję (prawdopodobnie ma to znaczenie tylko wtedy, gdy masz zyliony instancji kręcących się po okolicy, ale są do tego przypadki użycia).
object
typ jest niezmienny i nie można dodawać nowych atrybutów? Wydaje się, że miałoby to największy sens.