Was ist der Zweck von __slots__
in Python - vor allem im Hinblick darauf, wann ich es verwenden möchte und wann nicht?
Antworten
Zu viele Anzeigen?Die ursprüngliche Frage bezog sich auf allgemeine Anwendungsfälle und nicht nur auf Speicher. Es sollte hier also erwähnt werden, dass man auch bessere Leistung bei der Instanziierung großer Mengen von Objekten - interessant z. B. beim Parsen großer Dokumente in Objekte oder aus einer Datenbank.
Hier ein Vergleich der Erstellung von Objektbäumen mit einer Million Einträgen unter Verwendung von Slots und ohne Slots. Als Referenz auch die Leistung bei Verwendung von einfachen Dicts für die Bäume (Py2.7.10 auf OSX):
********** RUN 1 **********
1.96036410332 <class 'css_tree_select.element.Element'>
3.02922606468 <class 'css_tree_select.element.ElementNoSlots'>
2.90828204155 dict
********** RUN 2 **********
1.77050495148 <class 'css_tree_select.element.Element'>
3.10655999184 <class 'css_tree_select.element.ElementNoSlots'>
2.84120798111 dict
********** RUN 3 **********
1.84069895744 <class 'css_tree_select.element.Element'>
3.21540498734 <class 'css_tree_select.element.ElementNoSlots'>
2.59615707397 dict
********** RUN 4 **********
1.75041103363 <class 'css_tree_select.element.Element'>
3.17366290092 <class 'css_tree_select.element.ElementNoSlots'>
2.70941114426 dict
Testklassen (ident, abgesehen von Slots):
class Element(object):
__slots__ = ['_typ', 'id', 'parent', 'childs']
def __init__(self, typ, id, parent=None):
self._typ = typ
self.id = id
self.childs = []
if parent:
self.parent = parent
parent.childs.append(self)
class ElementNoSlots(object): (same, w/o slots)
Testcode, ausführlicher Modus:
na, nb, nc = 100, 100, 100
for i in (1, 2, 3, 4):
print '*' * 10, 'RUN', i, '*' * 10
# tree with slot and no slot:
for cls in Element, ElementNoSlots:
t1 = time.time()
root = cls('root', 'root')
for i in xrange(na):
ela = cls(typ='a', id=i, parent=root)
for j in xrange(nb):
elb = cls(typ='b', id=(i, j), parent=ela)
for k in xrange(nc):
elc = cls(typ='c', id=(i, j, k), parent=elb)
to = time.time() - t1
print to, cls
del root
# ref: tree with dicts only:
t1 = time.time()
droot = {'childs': []}
for i in xrange(na):
ela = {'typ': 'a', id: i, 'childs': []}
droot['childs'].append(ela)
for j in xrange(nb):
elb = {'typ': 'b', id: (i, j), 'childs': []}
ela['childs'].append(elb)
for k in xrange(nc):
elc = {'typ': 'c', id: (i, j, k), 'childs': []}
elb['childs'].append(elc)
td = time.time() - t1
print td, 'dict'
del droot
Sie haben - im Grunde - keine Verwendung für __slots__
.
Für die Zeit, in der Sie denken, Sie bräuchten __slots__
verwenden möchten, müssen Sie eigentlich Leichtgewicht o Fliegengewicht Entwurfsmuster. Dies sind Fälle, in denen Sie keine reinen Python-Objekte mehr verwenden wollen. Stattdessen wollen Sie eine Python-Objekt-ähnliche Hülle um ein Array, eine Struktur oder ein Numpy-Array.
class Flyweight(object):
def get(self, theData, index):
return theData[index]
def set(self, theData, index, value):
theData[index]= value
Der klassenähnliche Wrapper hat keine Attribute - er bietet lediglich Methoden, die auf die zugrunde liegenden Daten wirken. Die Methoden können auf Klassenmethoden reduziert werden. Man könnte sie sogar auf Funktionen reduzieren, die auf das zugrunde liegende Datenfeld wirken.
- See previous answers
- Weitere Antworten anzeigen