python 2.5.x memory management

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

hallo,

in meinem projekt habe ich mittlerweile fuer speichereffizienz mehrere singleton klassen die eine dynamische anzahl von objekten verwalten.

wie kann ich sicherstellen dass beim beenden von python das singleton mit zerstoert wird so dass am ende der speicher mit freigegeben wird?

kann man es irgendwie in die liste fuer den garbage collector eintragen oder aehnliches?

besten gruss,
t
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Wenn ein Prozess beendet wird (in diesem Fall der Python Interpreter) wird vom Betriebssystem automatisch der gesamte belegte Speicher wieder frei gegeben. Darum musst du dich nicht kümmern.

Generell musst du dir bei Python keine Gedanken um Speicherverwaltung machen. Genau dafür ist ja der GC da. Ich verstehe auch nicht, wie dir Singletons dabei helfen sollen. Das hört sich für mich nach einem Design Fehler an. Vor allem, wenn du die Singletins hauptsächlich für die Reduzierung des Speichrverbrauchs nutzt, läuft da sicher etwas falsch bei dir. Vielleicht solltest du das mal etwas weiter ausführen.
Bottle: Micro Web Framework + Development Blog
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

hallo defnull
danke fuer die antwort.

ja, mag sein dass es besser gemacht werden kann. mir ist auf die schnelle nur das eingefallen. vielleicht weisst du ja was besseres, sonst funktioniert mein code soweit.

problem :
ich habe zig files die immer wieder gelesen werden. ich will moeglichst die plattenzugriffe reduzieren.

loesung:
singleton das die files zwischenspeichert und read zugriffe abfaengt. wurde die file bereits gelesen, wird sie aus dem selbstgemachten cache kopiert, sonst in ausgelesen und dann zwischengespeichert.

so reduziere ich meine zugriffe auf 1x und spar in meinen berechnungen viel viel zeit.

ich will nur sichergehen dass alles automatisch & sauber freigegeben wird.
code im anhang:

fuer alternativen bin ich immer offen!
gruss und danke,
t

ps: frage mich grad warum ich keine hashtable benutze...

Code: Alles auswählen

class VolumeStorage(Singleton):
    """
    VolumeStorage
    """
    
    _volumeList = [];
    
    def append(self,volumePair):
        self._volumeList.append(volumePair);
    
    def get(self,volumeKey):
        """
        get: return a volume volume 
        """
        
        numberVolumes = len(self._volumeList);
        found = False;
        
        index = 0;
        
        
        while not found and index < numberVolumes:
            volumePair = self._volumeList[index];
            
            found = volumePair.key == volumeKey;
            
            if not found:
                index = index +1;
            
        if not found:
            return None;
        else:
            volumePair = self._volumeList[index];
            from pytom_volume import vol;
            volume = volumePair.volume;
            returnVolume = vol(volume.sizeX(),volume.sizeY(),volume.sizeZ());
            returnVolume.copyVolume(volumePair.volume);
            return returnVolume;
        
        
    def delete(self):
        """
        delete: Should be called before python is shut down for proper memory deallocation 
        """
        
        for volumePair in self._volumeList:
            
            del(volumePair.volume);
            del(volumePair);

        self._volumeList = [];

def read(filename,subregionX=0,subregionY=0,subregionZ=0,subregionXL=0,subregionYL=0,subregionZL=0,samplingX=0,samplingY=0,samplingZ=0,binningX=0,binningY=0,binningZ=0):
    """
    read: Will read a file either from disk, or copy the identical volume if file has already been read from disk. -> no disk access for data.
    """
    #import time;
    #print time.time();
    volumeStorage = VolumeStorage();
    key = filename + subregionX.__str__() + subregionY.__str__() + subregionZ.__str__() + subregionXL.__str__() + subregionYL.__str__() + subregionZL.__str__() + samplingX.__str__() + samplingY.__str__() + samplingZ.__str__() + binningX.__str__() + binningY.__str__() + binningZ.__str__();
    volume = volumeStorage.get(key);

    if not volume:
        from pytom_volume import read as readFromDisk;
        
        volume = readFromDisk(filename,int(subregionX),int(subregionY),int(subregionZ),
                                       int(subregionXL),int(subregionYL),int(subregionZL),
                                       int(samplingX),int(samplingY),int(samplingZ),
                                       int(binningX),int(binningY),int(binningZ));
        
        volumeStorage.append(VolumeKeyPair(volume,key));
    
    #print time.time();
    return volume;

Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Was machen die ganzen Semikola da oO

Warum liest du nicht einfach am Anfang alle Dateien ein und das wars? Da braucht man doch komischen Singleton-Hacks und sowas.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

`del` ist keine Funktion, schreibe also `del name`

Deine `delete`-Methode laesst sich auch `self._volumeList = []` minimieren und ich bin mir sicher, dass dein Verstaendnis von `del` falsch ist.

Zu `_volumeList`: warum verwendest du das Klassenattribut, als waere es ein Exemplarattribut?

Zum Singleton: Warum nicht einfach einmal erstellen?
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

@dauerbaustelle
1. ; kommt davon wenn man mit vielen sprachen arbeitet. man braucht einen kleinsten gemeinsamen nenner was syntax angeht, und da python ; auch vertraegt bleiben die im code

2. files werden on demand gelesen. sonst ist es ja nicht effizient wenn ich einen riesenteil daten lese wo ich eventuell nur die haelfte brauchen werde


@cofi
1. del -> 'del name' ?
kann sein dass ich da was falsch verstanden habe. was ist denn das richtige verstaendniss von del?
ich denk zuviel in C

2. was ist der unterschied zwischen normalen attributen , _attributen und exemplarattributen?

3. Zum Singleton: Warum nicht einfach einmal erstellen?
wie meinen?
BlackJack

@thomas15: Du machst da ein paar sehr komische Sachen. Der Sinn des Caches Plattenzugriffe zu minimieren ist ja okay, aber das hat mit Speicherverwaltung nichts zu tun. Darum brauchst Du Dich in Python in der Regel *gar nicht kümmern*! Der Kommentar und der Inhalt bei der `delete()`-Methode zeigen, dass Du da was grundsätzlich nicht verstanden hast. ``del`` gibt zum Beispiel keinen Speicher frei. Das macht der GC *vielleicht* in der Folge von einem ``del``, aber damit kann man keine Speicherfreigabe erzwingen. Die allerletzte Zeile in `delete()` hätte für den Effekt vollkomment ausgereicht. Die Methode sollte dann auch besser `clear()` heissen, weil sie eben nur den Cache leert.

Was macht die `Singleton`-Klasse? Die scheint mir hier überflüssig, weil sich das Programm genauso verhalten sollte wenn man einfach von `object` erbt.

Die `get()`-Methode ist furchtbar umständlich. Selbst wenn man eine Liste statt eines Dictionaries verwendet kann man das deutlich einfacher und kürzer schreiben.

Importe sollte man nicht tief in Funktionen verstecken, die gehören an den Anfang eines Moduls wo man sie sehen kann.

Man könnte für `VolumeStorage` die Methoden `__getitem__()` und `__setitem__()` implementieren statt `append()` und `get()`. Für Ausnahmefälle gibt's auch Ausnahmen. Statt eines "Fehlerwertes" würde sich hier das auslösen eines `KeyError` anbieten.

Warum rufst Du `__str__()` explizit auf? Solche magischen Methoden sollte man von aussen nicht aufrufen wenn es sich vermeiden lässt. Dafür gibt's die `str()`-Funktion.

Der Schlüssel ist auch nicht besonders intelligent aufgebaut, weil da potentiell Kollisionen entstehen können. '12' + '3' ist ja das gleiche wie '1' + '23'. Da sollten also Trennzeichen zwischen die Bestandteile. Wobei die Berechnung des Schlüssels IMHO sowieso in die `VolumeStorage`-Klasse gehört, denn das ist ein Implementierungsdetail davon. Was der Cache intern als Schlüssel verwendet, geht "aussen" niemanden etwas an. Man könnte da statt einer Zeichenkette zum Beispiel genausogut ein Tupel aus dem Dateinamen und den Zahlen nehmen. Die `VolumeKeyPair`-Klasse sollte, falls man denn bei einer Liste bleibt, ausserhalb der Cache-Klasse auch nicht bekannt sein. Und sie ist auch ein wenig übertrieben wenn man stattdessen auch ein Tupel verwenden könnte.

Die Anzahl der Argumente bei `read()` finde ich ein wenig zu hoch. Da könnte man gut welche zusammenfassen, zum Beispiel bei den X/Y/Z-Werten die zusammengehören ein Tupel oder eine Sequenz übergeben.

Insgesamt macht der Quelltext den Eindruck dass Du nicht wirklich in Python programmierst. Deine Vorstellungen von Speicherverwaltung und die ganzen Semikolons deuten darauf hin.

Cofi meinte mit 3. einfach `VolumeStorage` nur einmal erstellen. Also zum Beispiel gleich nach der Klassendefinition ``VOLUME_STORAGE = VolumeStorage()`` hinschreiben und dann im Programm `VOLUME_STORAGE` verwenden. Eben das einmal erstellte Exemplar. Damit ist das doch ein Singleton. Nur eben kein "erzwungenes".

Vielleicht wäre das weglassen des Semikolons der erste Schritt *wirklich* Python zu schreiben. Wenn man in mehreren Sprachen nur Quelltext auf dem kleinsten gemeinsamen Nenner schreibt, dann produziert man sehr wahrscheinlich in allen bis auf einer der Sprachen untypischen, komischen Quelltext, weil man dann eigentlich in einer anderen Sprache schreibt, nur eben mit angepasster Syntax. Sprachen sind aber mehr als Syntax. Da gehört auch die idiomatische Anwendung dazu.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Hab ich es mir doch gedacht: Du hast das Problem tot-optimiert ;)

Das Betriebssystem (ja, sogar Windows) cached Lesezugriffe sowieso im Arbeitsspeicher. Völlig transparent. Du musst dich darum überhaupt nicht kümmern. Im Gegenteil: Je mehr Speicher dein eigenes Programm belegt, desto weniger RAM bleibt für die Read-Caches des Betriebssystems.

Du kannst gerne file-objekte cachen (also ein Singleton, das vom Dateinamen abhängt) aber den Inhalt der Dateien würde ich auf keinen Fall im Speicher halten.

Es sei denn, die Berechnung, die du damit anstellst, ist dermaßen aufwendig, das du CPU sparen willst. Aber laut deiner Aussage geht es dir ja hauptsächlich um Speicher und Festplattenzugriffe.
Bottle: Micro Web Framework + Development Blog
BlackJack

@defnull: Grundsätzlich hast Du Recht, aber es gibt Ausnahmen, nämlich dann wenn die Daten die man da zusammensammelt nicht so hübsch "linear" in der Datei liegen und damit nicht effizient vom BS gecachet werden können und/oder wenn die Daten nicht nur gelesen sondern auch berechnet werden. Zum Beispiel wenn man auf Platte ein 3D-Array hat und davon einen Unterwürfel einlesen will und dabei auch gleich mehrere Werte aggregiert werden oder eine Schrittweite, also sozusagen das dritte Argument bei der Slice-Notation, vorgegeben ist.

Ich kenne die Bibliothek nicht, die der OP verwendet, aber die Argumente könnten auf so etwas hindeuten.

@thomas15: Du solltest auf jeden Fall messen ob es wirklich etwas bringt.
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

der code ist natuerlich nur ein ausschnitt so das es schwer nachzuvollziehen ist was passiert.
im program selbst wirden C++ klassen interfaced durch swig. da ich moeglichst wenig durch den swig teil gehen will moechte ich wenig reads vermeiden. ausserdem plattenzugriffe allgemein.
ich kann leider nicht davon ausgehen dass die files im cache bleiben, deswegen zwinge ich sie dazu weil so viele files da sind, dass sie sich selbst ausm cache rausschieben
ausserdem werden die files beim lesen gefiltert, so dass der prozess auch 1000x wiederholt wuerde, wobei das ergebniss nicht im cache bleibt.
soweit, sogut.

ich glaub die diskusion hat mir ein paar neue blickpunkte vermittelt. da ich hier der einzige code-knecht bin ist es schwer feedback zum eigenen code zu bekommen.
danke vielmals fuer die rege beteiligung.

ps:
witzig das die python community so stolz darauf ist dass es kein ; gibt. :D


@blackjack
1 Was macht die `Singleton`-Klasse? Die scheint mir hier überflüssig, weil sich das Programm genauso verhalten sollte wenn man einfach von `object` erbt.

Implementiert das Singleton - Pattern

2 Importe sollte man nicht tief in Funktionen verstecken, die gehören an den Anfang eines Moduls wo man sie sehen kann.

geb ich dir vollkommen recht, nur sollten importe nicht auftreten wenn man ein modul nicht braucht -> ineffizient.

3 Warum rufst Du `__str__()` explizit auf? Solche magischen Methoden sollte man von aussen nicht aufrufen wenn es sich vermeiden lässt. Dafür gibt's die `str()`-Funktion.
macht das einen grossen unterschied? ist da eine python philosophie dahinter die an mir vorbeiging?
ich wuerd mir mal erklaeren dass die str(objekt) funktion auch die __str__() funktion aufruft. so umgehe ich einen funktionsaufruf... lieg ich da falsch?

4 Die Anzahl der Argumente bei `read()` finde ich ein wenig zu hoch. Da könnte man gut welche zusammenfassen, zum Beispiel bei den X/Y/Z-Werten die zusammengehören ein Tupel oder eine Sequenz übergeben.
Stimmt, es ist leider unuebersichtlich, aber dafuer hab ich ja noch eine andere read funktion ueberladen die nur einen filename hat. Ausserdem sind das C++ funktionen die man nicht mal eben anpassen kann.

5 ;
ja mei, idiomatisch hin, her. ich glaub das man den code mit und ohne ; gut versteht. aber ich werd mich bessern... :twisted:

danke fuer die vorschlaege. wenn jemand mein verstaendniss von 3 zurechtbiegen koennte waere ich froh.


@defnull
1 tot-optimiert
Jop, stimmt! 8)

2 Es sei denn, die Berechnung, die du damit anstellst, ist dermaßen aufwendig, das du CPU sparen willst. Aber laut deiner Aussage geht es dir ja hauptsächlich um Speicher und Festplattenzugriffe.
wie oben erwaehnt brauch ich das zwischenergebniss. haette ich wohl am anfang erwaehnen sollen, sorry. mir gigs halt um die frage was am ende so mit meinem speicher los ist.
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

@blackjack:
ja, ich denke schon dass es einiges rausreisst. vor allem umgehe ich das wiederholte filtern auf platte.

danke fuer euere zeit!
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

thomas15 hat geschrieben:dass die str(objekt) funktion auch die __str__() funktion aufruft. so umgehe ich einen funktionsaufruf... lieg ich da falsch?
Glaubst du wirklich, dass dein Programm dann in irgend einer Weise schneller wird?!

Du könntest für dieses Caching eine Klassenmethode verwenden, etwa so:

Code: Alles auswählen

class Volume(object):
    cache = dict()

    @staticmethod
    def generate_cache_key(...):
        return unique cache key

    def fromfile(self, filename, ...):
        cls = self.__class__
        cache_key = cls.generate_cache_key(filename, ...)
        cached_volume = cls.cache.get(cache_key)
        if cached_volume is None:
            cached_volume = cls.cache[cache_key] = cls(...)
        return cached_volume
Ganz ohne Hacks, Singletons und so weiter.
Zuletzt geändert von Dauerbaustelle am Donnerstag 29. April 2010, 13:41, insgesamt 2-mal geändert.
Gabelmensch
User
Beiträge: 79
Registriert: Montag 12. Oktober 2009, 11:50

Ich kopiere Dateien die mehrfach nacheinander bearbeitet werden sollen, vorher in eine Ramdisk. :mrgreen:
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

@dauerbaustelle
thomas15 hat folgendes geschrieben:
dass die str(objekt) funktion auch die __str__() funktion aufruft. so umgehe ich einen funktionsaufruf... lieg ich da falsch?


Glaubst du wirklich, dass dein Programm dann in irgend einer Weise schneller wird?!
warum sollte es nicht? ist da ein grund dahinter warum man str(object) uber __str__() bevorzugen sollte, ausser dass man es 'sollte'?

Du könntest für dieses Caching eine Klassenmethode verwenden, etwa so:
auch ganz nett, vielleicht kann ich das fuer andere faelle anwenden.

der vorteil bei meiner methode ist dass mein singleton read die gleichen parameter nimmt wie das read ohne. beide sind demnach immer austauschbar.

@abelmensch
auch ne moeglichkeit. :D
BlackJack

@thomas15: Es gibt ja ein ``;``, nur ist das eben nicht zum Abschliessen von einzelnen Anweisungen sondern nur zum Trennen von mehreren Anweisungen da. Und deshalb bei einer Anweisungen pro Zeile nicht notwendig. Das ist ganz nett, weil man etwas weniger eigentlich unnötige Interpunktion tippen muss, aber wirklich "stolz" ist das wohl niemand drauf. Wo ich stolz drauf bin, ist dass es nicht so verkorkst wie zum Beispiel in C++ ist, wo ein Semikolon am Ende eines grösseren Konstruktes die Bedeutung davon entscheident verändern kann. Was man gerne mal übersieht und zu 'ner Menge Frust, zumindest bei Anfängern, führen kann.

Ad 1) Brauchst Du das Singleton-Muster denn? Das Programm verhält sich wie gesagt genau so wenn man einfach nur von `object` erbt. Es macht also keinen wirklichen Unterschied. Man hat dann halt das Borg-Muster -- zwar verschiedene Objekte, aber alle verhalten sich als wären sie das selbe. Nur der Identitätstest weicht ab, aber den brauchst Du ja nicht.

Ad 2) Hast Du nachgemessen, dass die Importe ineffizient sind? Wieviele Sekunden Gewinn bringt das? Mikrosekunden? Überhaupt vernünftig messbar? Man könnte genau so argumentieren, dass bei Dir bei jedem Durchlauf des entsprechenden Codeteils etwas Zeit für das ausführen der ``import``-Anweisung drauf geht. Was man auch als ineffizient ansehen kann. Solange so ein ``import`` nicht wirklich "teuer" ist *und* man sich 100% sicher ist, dass man ihn nicht irgendwann sowieso braucht, dann zieht das Argument nicht. Wenn in Deinem Programm auch nur ein einziges mal die `read()`-Funktion aufgerufen und der Cache verwendet wird, dann werden diese ``import``\e beide gebraucht. Und wenn sie nicht *wirklich* lange brauchen, gehören sie IMHO auch an den Anfang des Moduls wenn man sich nicht sicher ist, dass die `read()`-Funktion aufgerufen wird. Die paar einmaligen Mikrosekunden sind es nicht wert das man sich irgendwann mal dumm und dämlich sucht welche Abhängigkeiten ein Modul eigentlich hat.

Ad 3) "`__magic__`"-Namen sind nicht zur direkten Verwendung gedacht. Da wäre dann wirklich Python-Philosophie an Dir vorbeigegangen. Die Methoden sind zum Implementieren von besonderem Verhalten da um mit anderen, *offiziellen* Bestandteilen der Sprache zu interagieren. `__str__()` zum Beispiel mit der `str()`-Funktion. Wenn man `__str__()` direkt aufrufen sollte, bräuchte es `str()` ja nicht. Wenn Du an der Stelle einen Funktionsaufruf sparen möchtest, kann es übrigens durchaus sein, dass Du an der falschen Stelle "sparst", denn die "Grundmethoden" könnten in einer Implementierung durchaus effizienter nachgeschlagen als Attribute. Es kann also durchaus sein, dass eine Implementierung von `str()` schneller an die Methode herankommt, als ein normaler Attributzugriff von aussen. Und selbst wenn man durch `__str__()` etwas gewinnt, wäre hier wieder die Frage *was* Du da eigentlich *wirklich* sparst, und ob es das Wert ist.

Ad 4) Was hat die Argumentliste der C++-Funktion mit der Python-Funktion zu tun? Man muss sowas ja nicht "durchschleifen", sondern kann das auf der Python-Seite durchaus auch etwas hübscher verpacken.

@Dauerbaustelle: Iiih jetzt benutzt Du auch noch `__magic__` in Deiner `fromfile()`. Gibt es einen Grund warum Du die nicht als `classmethod()` "deklarierst"?

@thomas15: Das ist kein Alleinstellungsmerkmal von Deinem `read()`, denn entweder machst Du da wie vorgeschlagen eine `classmethod()` draus, oder Du erstellst einmal so ein `Volume`-Objekt. In beiden Fällen würde `fromfile()` die gleichen Argumente wie Deine `read()` nehmen und damit auch wieder austauschbar sein.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

BlackJack hat geschrieben:@Dauerbaustelle: Iiih jetzt benutzt Du auch noch `__magic__` in Deiner `fromfile()`. Gibt es einen Grund warum Du die nicht als `classmethod()` "deklarierst"?
Hoorks, weiß auch nicht was ich da geschrieben hatte o__O

Muss natürlich so lauten:

Code: Alles auswählen

class Volume(object):
    cache = dict()

    @staticmethod
    def generate_cache_key(...):
        return unique cache key

    @classmethod
    def fromfile(cls, filename, ...):
        cache_key = cls.generate_cache_key(filename, ...)
        cached_volume = cls.cache.get(cache_key)
        if cached_volume is None:
            cached_volume = cls.cache[cache_key] = cls(...)
        return cached_volume
PS: Das "auch" suggeriert mir, dass der Rest auch bescheiden ist. Irre ich mich da und wenn nein, was ich schlecht daran? :-)
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

meine singleton klasse sieht so aus
vergesst mal die ;

Code: Alles auswählen

class Singleton(object):
    """
    Singleton: Abstract class used for singleton classes. Most children will be used for efficient memory management to speed up things. 
    """
    
    def __new__(cls, *a, **k):
        if not hasattr(cls, '_inst'):
            cls._inst = super(Singleton, cls).__new__(cls, *a, **k);
            
        return cls._inst;
http://de.wikipedia.org/wiki/Singleton_ ... rg-Pattern

Unterschied zu Borg? Mag sein dass ich beim Suchen nach Singleton Mustern zufaellig das Borg muster implementiert hab, zumindest find ich beim googlen grad den gleichen konstrukor dafuer.

So wie ich das verstehe sind dann nach aussen verschiedene objekte die sich aber nach innen den speicher teilen. oder?
thomas15
User
Beiträge: 98
Registriert: Montag 7. April 2008, 19:07

korrektur

mein source und der borg source sind unterschiedlich.
sorry, mach das hier mit nur einem auge.

trotzdem hab ich immernoch unwissen zum borg pattern

zusaetzliche frage
implementiert object dann auch Borg ?
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

thomas15 hat geschrieben:zusaetzliche frage
implementiert object dann auch Borg ?
Wie meinst du die Frage?

Zu deinem eigentlich Problem: Speicher deine Daten einfach in einer Klassenvariable. Klassen sind immer Singletons.
BlackJack

@Dauerbaustelle: Nein das "auch" bezog sich darauf das Du neben dem OP jetzt auch noch __magic__ verwendest. Ist vielleicht ansteckend. :-)

@thomas: Beim Borg-Muster hat man zwar unterschiedliche Objekte, die aber alle den gleichen Zustand teilen. Ist in Python halt einfacher weil man kein `__new__()` braucht. Das ist eher etwas "exotisch".

IMHO ist das einfachste aber immer noch das "Singleton" dadurch zu erreichen, dass man ganz einfach nur ein Exemplar davon erstellt und das dann verwendet. Damit lässt man sich auch die Flexibilität bei Bedarf eben doch mehr als eins zu erzeugen. Denn gerade dieser Fall hier gibt das ja gar nicht zwingend vor.

`object` ist kein "Borg", aber zumindest bei Python 2.x sollte man davon erben statt von "nichts", damit man eine "new style" Klasse bekommt. Auf den "old style"-Klassen funktionieren zum Beispiel "properties" nicht.

Die Doku in dem Singleton und auch der andere Quelltext und Deine Fragen machen ein wenig den Eindruck als wenn Du viel zu viel Gewicht auf Speicherverbrauch und Geschwindigkeit legst. Und zwar ohne den tatsächlichen Bedarf dafür festgestellt zu haben. Du produzierst "hässlichen" weil "unpythonischen" Quelltext in der *vagen Hoffnung* das wäre schneller. Selbst wenn, sind das alles nur Mikrooptimierungen, die ganz locker von so umständlichem Code wie in der gezeigten `get()`-Methoden um ein Vielfaches überschattet wird.
Antworten