Seite 1 von 1
Für und gegen __slots__
Verfasst: Mittwoch 15. November 2006, 11:58
von BlackJack
Weil kritisieren so'n Spass macht: Warum zum Henker benutzt Du `__slots__`? Wieviele Vokabeln erwartest Du in einer Datei, dass es Probleme mit dem Speicherverbrauch geben könnte?
Insbesondere bei der Vokabelliste, wo ich irgendwie nur eine handvoll Exemplare pro Programmlauf sehe.
Edit (Leonidas): Vom Thread Welches Datenbanksystem? getrennt.
Verfasst: Mittwoch 15. November 2006, 12:16
von gerold
BlackJack hat geschrieben:Warum zum Henker benutzt Du `__slots__`?
[...]
Insbesondere bei der Vokabelliste
Hi BlackJack!
Das ist ein berechtigter Einwand.
In der Klasse ``Vocable`` dachte ich wirklich an einen Geschwindigkeitsvorteil. In der Klasse ``Vocabulary`` bringt es aber (bis auf die Einschränkung, dass man von Außen keine neuen Attribute erstellen kann) gar nichts.
Wir rechnen ja mit bis zu 8.000 Vokabeln. Glaubst du nicht, dass ``__slots__`` in der Klasse ``Vocable`` einen Geschwindigkeitsvorteil bringt?
lg
Gerold

Verfasst: Mittwoch 15. November 2006, 12:50
von BlackJack
gerold hat geschrieben:Wir rechnen ja mit bis zu 8.000 Vokabeln. Glaubst du nicht, dass ``__slots__`` in der Klasse ``Vocable`` einen Geschwindigkeitsvorteil bringt?
Kann sein und wie gross ist der? Ist der bei 10K Vokabeln spürbar? Beim einlesen von Platte überhaupt vorhanden weil das Programm sowieso schneller ist als die Festplatte Daten liefern kann? Das sieht extrem nach "premature optimization" aus.
`__slots__` ist so eine Sache die ich lieber verschweige, weil sie insbesondere Umsteiger von anderen Sprachen auf dumme Ideen bringt ("final"/"es ist schneller/kleiner"). Solange man kein Problem mit dem Speicherverbrauch hat, sollte man `__slots__` nicht kennen müssen. IMHO.
Verfasst: Mittwoch 15. November 2006, 13:16
von gerold
BlackJack hat geschrieben:gerold hat geschrieben:Geschwindigkeitsvorteil
Das sieht extrem nach "premature optimization" aus.
`__slots__` ist so eine Sache die ich lieber verschweige, weil sie insbesondere Umsteiger von anderen Sprachen auf dumme Ideen bringt ("final"/"es ist schneller/kleiner").
Hi BlackJack!
Jein...
Ich schütze mich beim Programmieren gerne selber vor Fehlern. Deshalb setze ich auch ab und an mal ``assert`` ein um z.B. einen übergebenen Parameter zu prüfen oder ich schränke ab und an auch eine Klasse mit ``__slots__`` ein, damit ich den Klasseninstanzen keine falsch geschriebenen Attribute zuweisen kann.
Das hat dann nichts mit Geschwindigkeitsoptimierung zu tun.
Code: Alles auswählen
class GlobalConstants(object):
__slots__ = ("vorname", "nachname")
gconst = GlobalConstants()
gconst.vorname = "Gerold"
gconst.nachname = "Penz"
gconst.VorName = "Nudlaug"
#AttributeError: 'GlobalConstants' object has no attribute 'VorName'
Das ist für mich irgendwie auch eine Qualitätskontrolle -- schon während dem Schreiben des Quellcodes.
Deshalb möchte ich ich die Existenz von ``__slots__`` nicht unbedingt verweigern.
lg
Gerold

Verfasst: Mittwoch 15. November 2006, 14:18
von sape
Hmm, '__slots__' kannte ich bis her nicht. Ich finde die möglichkeit echt gut, das man damit bewirken kann, keine Atribute extern einer Klasse zuzuweisen. Sollte man slots aus diesem grund nicht einsetzen? Gerade deswegen würde eich das gerne _jetzt_ permanent benutzen

Ich finde der einwand das der Programmierer sleber vor fehlern geschützt wird berechtigt.
Daher verstehe ich deinen Einwand nicht BlackJack

Wann genau sollte man slots benutzen und warum sollte man tunlichst slotst vereiden?
lg
Verfasst: Mittwoch 15. November 2006, 15:06
von BlackJack
Genau das meine ich mit auf dumme Ideen bringen. Dafür ist `__slots__` nicht gedacht. Vor so etwas warnt einen zum Beispiel `PyLint`.
Auf Objekte mit `__slots__`, auch wenn sie nur geerbt sind, kannst Du keine `weakrefs` setzen, Du kannst sie nicht picklen, in Subklassen ist der "Schutz" dann auch schon wieder weg, die Probleme bleiben aber. Und Mehrfachvererbung funktioniert nicht wenn mehr als eine Klasse `__slots__` besitzt. Man kann die Objekte auch nicht mehr mit beliebigen Attributen dekorieren. Das muss ja nicht immer ein Fehler sein.
Viel zu viele Probleme bzw. Verhaltensänderungen gegenüber normalen Klassen/Objekten. Wie oft hilft Dir das bei Vertippern? Kann man das nicht mit einem Editor lösen der Autovervollständigungen vorschlägt? Und fallen solche Probleme beim Testen nicht sehr schnell auf?
Das mit dem picklen ist im vorliegenden Fall zum Beispiel ein ziemlicher Minuspunkt. Warum sollte man Vokabeln nicht picklen können?
Verfasst: Mittwoch 15. November 2006, 15:47
von gerold
BlackJack hat geschrieben:nicht picklen [...] Mehrfachvererbung funktioniert nicht [...] Verhaltensänderungen gegenüber normalen Klassen/Objekten
Hi BlackJack!
Ja, das sind
gewichtige Gegenargumente. Der Rest war mir zwar ziemlich "Wurst", aber so gesehen muss ich dir zustimmen. Danke für die Aufklärung.
Es scheint so, dass die Gegenargumente überwiegen. Ich werde ``__slots__`` nur mehr gezielt einsetzen wenn es gebraucht wird.
lg
Gerold

Verfasst: Mittwoch 15. November 2006, 15:51
von BlackJack
Ich habe mal folgendes Programm auf meinem Rechner laufen lassen:
Code: Alles auswählen
import os
import re
SLOT_RE = re.compile('^ *__slots__.*=')
CLASS_RE = re.compile('^ *class .*:')
def python_filenames(start_path):
for path, dummy, filenames in os.walk(start_path):
for filename in filenames:
if filename.endswith('.py'):
yield os.path.join(path, filename)
def multifile_iter(filenames):
for filename in filenames:
print filename
lines = open(filename, 'r')
for line in lines:
yield line
lines.close()
def count_classes_and_slots(lines):
classes = 0
slots = 0
for line in lines:
if CLASS_RE.match(line):
classes += 1
elif SLOT_RE.match(line):
slots += 1
return (classes, slots)
def main():
path = '/usr/lib/python2.4'
print count_classes_and_slots(multifile_iter(python_filenames(path)))
if __name__ == '__main__':
main()
Das Ergebnis: nur 82 von 17811 Klassen auf meinem System benutzen `__slots__`. Da sind eine ganze Menge "externe" Packages installiert. Wenn ich es auf die "jungfräuliche" Python2.5-Installation loslasse kommen 73 von 3987 Klassen heraus.
Bei den ganzen Zusatzpaketen der 2.4er Installation sind also gerade mal ca. 10 zusätzliche Klassen mit `__slots__`, wenn man unterstellt das sich deren Anzahl in der Standardbibliothek nicht stark verändert hat.
Verfasst: Mittwoch 15. November 2006, 16:12
von sape
OK, hast mich überzeugt. Dann lasse ich die Finger weg von '__slots__' da die Gegenargumente gewaltig sind und ich bis her ehe keine Verwendung dafür hatte.
Aber was genau ist den der Vorteil von '__slots__'? Soll man das nur benutzen wenn man im vornherein weis das man es mit z.B. ca. 100.000 Datensätzen zu tun hat?
lg
Verfasst: Mittwoch 15. November 2006, 16:39
von BlackJack
Der Vorteil von `__slots__` ist weniger Speicherverbrauch pro Objekt. Wenn man `__slots__` angibt, dann wird für jedes Attribut ein fester Platz in einem Array reserviert wo ein Pointer auf das Objekt gespeichert werden kann.
Ohne `__slots__` werden die Attribute in einem Dictionary gespeichert, das immer ein wenig mehr Speicher vorhalten muss als für die Attribute notwendig ist, damit der Zugriff auf die Hashtabelle effizient bleibt.
Ich würde `__slots__` nur einsetzen, wenn wirklich nachweislich zuviel Speicher verbraucht wird. Wenn ein Objekt 1 bis 2 KB verbraucht, und das scheint mir schon relativ gross, dann sind das bei 100000 Objekten "nur" 100 bis 200 MB. Ist zwar schon eine Menge, aber durchaus verkraftbar für heutige RAM-Grössen.
Und selbst dann könnte man noch überlegen, ob man wirklich alle Objekte gleichzeitig im Speicher benötigt oder nicht vielleicht auf Platte ausweichen kann. Die `__slots__` bringen ja nur einen Konstanten Speichergewinn pro Objekt, was Alex Martelli so in Newsgroup Posting von sich gibt: "some tenth of bytes", also nicht mehr als 100 Bytes pro Objekt. Wenn also ein Objekt 2 KB gross ist, dann bekommst Du in den 200 MB nur 5000 Objekte mehr untergebracht. Je grösser das einzelne Objekt desto kleiner der relative Gewinn.
Edit (Leonidas): Diskussion in Welches Dateiformat aufgesplittert, um meine Fehler wieder halbwegs auszubügeln.