Frage

In der Python-Datenmodell Referenzabschnitt auf Slots gibt es eine Liste von Hinweise zu __slots__ verwenden. Ich bin gründlich durch die 1. und 6. Artikel verwirrt, weil sie scheinen im Widerspruch zu einander sein.

Erster Eintrag:

  • Wenn Sie von einer Klasse erben, ohne __slots__, das __dict__ Attribut diese Klasse wird immer zugänglich, so ein __slots__ Definition in der Unterklasse ist bedeutungslos.

Sechster Punkt:

  • Die Wirkung eines __slots__ Erklärung wird auf die Klasse beschränkt wo es definiert ist. Als Ergebnis, Subklassen eine __dict__ haben es sei denn, sie definieren auch __slots__ (Die nur müssen Namen aller enthalten zusätzliche Slots).

Es scheint mir, diese Elemente besser formuliert oder durch Code angezeigt werden können, aber ich habe versucht, meinen Kopf um diese zu wickeln und bin immer noch kommen verwirrt. Ich verstehe, wie __slots__ ist sollte verwendet werden , und ich versuche, einen besseren Griff zu bekommen auf, wie sie funktionieren.

Die Frage:

Kann jemand mir bitte erklären, in einfacher Sprache, was die Bedingungen für die Vererbung von Slots sind, wenn Subklassen?

(Simple Codebeispiele wären hilfreich, aber nicht notwendig.)

War es hilfreich?

Lösung

Wie andere erwähnt haben, der einzige Grund für __slots__ definiert, ist etwas Speicher zu sparen, wenn Sie einfache Objekte mit einem vorgegebenen Satz von Attributen haben und nicht wollen, jeweils um ein Wörterbuch zu tragen. Dies ist nur sinnvoll, für die Klassen, von denen Sie planen, viele Instanzen zu haben, natürlich.

Die Einsparungen können nicht ohne weiteres ersichtlich sein - prüfen ...:

>>> class NoSlots(object): pass
... 
>>> n = NoSlots()
>>> class WithSlots(object): __slots__ = 'a', 'b', 'c'
... 
>>> w = WithSlots()
>>> n.a = n.b = n.c = 23
>>> w.a = w.b = w.c = 23
>>> sys.getsizeof(n)
32
>>> sys.getsizeof(w)
36

Von diesem würde es scheinen, die mit Schlitzen Größe ist größer als die No-Slots Größe! Aber das ist ein Fehler, denn sys.getsizeof berücksichtigt nicht „Objektinhalte“ wie das Wörterbuch:

>>> sys.getsizeof(n.__dict__)
140

Da allein die dict 140 Bytes nehmen, eindeutig die „32 Byte“ Objekt n wird behauptet, ist zu ergreifen, unter Berücksichtigung nicht alles, was in jedem Fall beteiligt ist. Sie können mit Erweiterungen von Drittanbietern einen besseren Job machen wie pympler :

>>> import pympler.asizeof
>>> pympler.asizeof.asizeof(w)
96
>>> pympler.asizeof.asizeof(n)
288

Dies zeigt viel deutlicher den Speicherbedarf, der durch __slots__ gespeichert ist: für ein einfaches Objekt wie dieser Fall ist es ein bisschen weniger als 200 Bytes, fast 2/3 der Gesamtgrundfläche des Objekts. Jetzt, da in diesen Tagen ein Megabyte mehr oder weniger nicht wirklich wichtig, dass alle viel zu den meisten Anwendungen ist dies auch, dass __slots__ erzählt, ist nicht wert, die Mühe, wenn Sie nur ein paar tausend Instanzen um zu einer Zeit haben werden - - jedoch für Millionen von Fällen, tut es sicher einen sehr wichtigen Unterschied machen. Sie können auch eine mikroskopische Speedup (teilweise aufgrund der besseren Cache-Nutzung für kleine Objekte mit __slots__) erhalten:

$ python -mtimeit -s'class S(object): __slots__="x","y"' -s's=S(); s.x=s.y=23' 's.x'
10000000 loops, best of 3: 0.37 usec per loop
$ python -mtimeit -s'class S(object): pass' -s's=S(); s.x=s.y=23' 's.x'
1000000 loops, best of 3: 0.604 usec per loop
$ python -mtimeit -s'class S(object): __slots__="x","y"' -s's=S(); s.x=s.y=23' 's.x=45'
1000000 loops, best of 3: 0.28 usec per loop
$ python -mtimeit -s'class S(object): pass' -s's=S(); s.x=s.y=23' 's.x=45'
1000000 loops, best of 3: 0.332 usec per loop

, aber das ist etwas abhängig von Python-Version (das sind die Zahlen, die ich mit 2,5 wiederholbar messen, mit 2,6, ich einem größerer relativer Vorteile sehe __slots__ für Einstellung ein Attribut, aber gar keine, in die Tat ein winziger dis Vorteil, für immer it).

Nun, in Bezug auf Vererbung: für eine Instanz dict-weniger, alle Klassen bis seine Vererbungskette muss auch dict-weniger Instanzen hat. Klassen mit dict losen Fällen sind solche, die __slots__ definieren, sowie die meisten eingebauten Typen (eingebauten Typen, deren Instanzen haben dicts sind diejenigen, auf deren Instanzen Sie beliebige Attribute wie Funktionen einstellen können). Überlappungen in Slot-Namen sind nicht verboten, aber sie sind nutzlos und etwas Speicher verschwenden, da Slots vererbt werden:

>>> class A(object): __slots__='a'
... 
>>> class AB(A): __slots__='b'
... 
>>> ab=AB()
>>> ab.a = ab.b = 23
>>> 

Wie Sie sehen, können Sie einstellen a auf einem AB Instanz Attribut - AB selbst definiert nur Slot b, aber es erbt Schlitz a von A. die geerbte Schlitz Repeating ist nicht verboten:

>>> class ABRed(A): __slots__='a','b'
... 
>>> abr=ABRed()
>>> abr.a = abr.b = 23

aber verschwendet ein wenig Speicher:

>>> pympler.asizeof.asizeof(ab)
88
>>> pympler.asizeof.asizeof(abr)
96

so gibt es wirklich keinen Grund, es zu tun.

Andere Tipps

class WithSlots(object):
    __slots__ = "a_slot"

class NoSlots(object):       # This class has __dict__
    pass

Erstes Element

class A(NoSlots):            # even though A has __slots__, it inherits __dict__
    __slots__ = "a_slot"     # from NoSlots, therefore __slots__ has no effect

Sechster Punkt

class B(WithSlots):          # This class has no __dict__
    __slots__ = "some_slot"

class C(WithSlots):          # This class has __dict__, because it doesn't
    pass                     # specify __slots__ even though the superclass does.

Sie werden wahrscheinlich nicht __slots__ in naher Zukunft verwenden müssen. Es ist nur auf Kosten einer gewissen Flexibilität speichern Speicher vorgesehen. Es sei denn, Sie Zehntausende von Objekten wird es keine Rolle.

  

Python: Wie funktioniert Vererbung von __slots__ in Subklassen tatsächlich funktioniert

     

bin ich gründlich vom 1. und 6. Artikel verwirrt, weil sie sich zu sein scheinen zu widersprechen.

Diese Elemente nicht widersprechen eigentlich einander. Die erste regards Subklassen von Klassen, die __slots__ nicht implementieren, die zweite regards Subklassen von Klassen, die nicht implementieren __slots__.

Subklassen von Klassen, die __slots__ nicht implementieren

ich zunehmend bewusst bin, dass so groß ist wie die Python-Dokumentation ist (zu Recht) den Ruf, zu sein sie sind nicht perfekt, vor allem in Bezug auf die weniger genutzten Funktionen der Sprache. Ich würde ändern die docs wie folgt:

  

Wenn Sie von einer Klasse ohne __slots__ erben, das __dict__ Attribut   diese Klasse wird immer zugänglich sein , so eine __slots__ Definition in   die Unterklasse ist sinnlos .

__slots__ ist nach wie vor sinnvoll für eine solche Klasse. Es dokumentiert die erwarteten Namen der Attribute der Klasse. Es auch schafft Slots für diese Attribute - sie werden die schnelleren Lookups bekommen und weniger Platz nutzen. Es erlaubt nur für andere Attribute, die die __dict__ zugewiesen werden.

Das Änderung rel="nofollow wurde angenommen und ist nun in der neueste Dokumentation .

Hier ist ein Beispiel:

class Foo: 
    """instances have __dict__"""

class Bar(Foo):
    __slots__ = 'foo', 'bar'

Bar hat nicht nur die Schlitze es erklärt, es hat auch Foo Slots - die __dict__ sind:

>>> b = Bar()
>>> b.foo = 'foo'
>>> b.quux = 'quux'
>>> vars(b)
{'quux': 'quux'}
>>> b.foo
'foo'

Subklassen von Klassen, die Sie implementieren __slots__

  

Die Wirkung einer __slots__ Erklärung auf die Klasse beschränkt, in denen es   ist definiert. Als Ergebnis haben Subklassen eine __dict__ es sei denn, sie   auch definieren __slots__ (die nur Namen der zusätzlichen enthalten   Slots).

Nun, das ist nicht ganz richtig nicht. Die Wirkung einer __slots__ Erklärung ist nicht ganz beschränkt sich auf die Klasse, in der sie definiert ist. Sie können Auswirkungen auf die Mehrfachvererbung, zum Beispiel.

würde ich das ändern:

  

Für die Klassen in einer Vererbungsbaum, der __slots__ definiert, Unterklassen wird eine __dict__ es sei denn, sie haben   auch definieren __slots__ (die nur Namen der zusätzlichen enthalten   Slots).

Ich habe es tatsächlich aktualisiert zu lesen:

  

Die Wirkung einer __slots__ Erklärung ist nicht auf die Klasse beschränkt   wo es definiert ist. __slots__ in Eltern erklärt sind in   Kind-Klassen. Allerdings wird Kind Subklassen eine __dict__ erhalten und   __weakref__ es sei denn, sie auch __slots__ definieren (die nur Namen von zusätzlichen Slots enthalten soll).

Hier ist ein Beispiel:

class Foo:
    __slots__ = 'foo'

class Bar(Foo):
    """instances get __dict__ and __weakref__"""

Und wir sehen, dass eine Unterklasse einer geschlitzten Klasse bekommt die Schlitze zu verwenden:

>>> b = Bar()
>>> b.foo = 'foo'
>>> b.bar = 'bar'
>>> vars(b)
{'bar': 'bar'}
>>> b.foo
'foo'

(Weitere Informationen über __slots__, siehe meine Antwort hier .)

Von der Antwort, die Sie verknüpfen:

  

Die richtige Verwendung von __slots__ ist Raum in Objekten zu speichern. Statt ein dynamisches dict mit ...

„Wenn aus einer Klasse ohne __slots__ erben, die __dict__ Attribut dieser Klasse wird immer zugänglich sein“, so Ihre eigene __slots__ Zugabe kann keine Objekte verhindern, dass ein __dict__ mit und kann nicht Platz sparen.

Das Bit über __slots__ nicht vererbt wird, ist ein wenig stumpf. Denken Sie daran, dass es ein magisches Attribut ist und verhält sich nicht wie andere Attribute, dann wieder gelesen, dass dieses magische Schlitze Verhalten mit den Worten, nicht vererbt wird. (Das ist wirklich alles, was es ist.)

Mein Verständnis ist, wie folgt:

  • Klasse X hat keine __dict__ <-------> Klasse X und deren Super alle angegebenen __slots__

  • In diesem Fall werden die tatsächlichen Schlitze der Klasse aus der Vereinigung von __slots__ Erklärungen besteht für X und deren Super; das Verhalten ist nicht definiert (und wird ein Fehler werden), wenn diese Vereinigung nicht disjunkt ist

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top