1180 Stimmen

Verwendung von __slots__?

Was ist der Zweck von __slots__ in Python - vor allem im Hinblick darauf, wann ich es verwenden möchte und wann nicht?

1voto

Red Pill Punkte 473

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

0voto

S.Lott Punkte 371691

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X