Wie kann ich mir eine Klasseninstanziierung in Python merken?

Ok, hier ist das reale Szenario: Ich schreibe eine Anwendung und habe eine Klasse, die einen bestimmten Dateityp repräsentiert (in meinem Fall handelt es sich um Fotos, aber dieses Detail ist für das Problem irrelevant). Jede Instanz der Photograph-Klasse sollte für den Dateinamen des Fotos eindeutig sein.

Das Problem ist, wenn ein Benutzer meiner Anwendung anweist, eine Datei zu laden, muss ich in der Lage sein, festzustellen, wann Dateien bereits geladen sind, und die vorhandene Instanz für diesen Dateinamen zu verwenden, anstatt doppelte Instanzen für denselben Dateinamen zu erstellen.

Für mich scheint dies eine gute Situation zu sein, um mit Memoization zu arbeiten, und es gibt viele Beispiele dafür, aber in diesem Fall speichere ich nicht nur eine gewöhnliche Funktion, ich muss es auch tun__init__(). Dies ist mit der Zeit ein Problem__init__() wird aufgerufen, es ist bereits zu spät, da bereits eine neue Instanz erstellt wurde.

Bei meinen Nachforschungen habe ich Pythons gefunden__new__() Methode, und ich war tatsächlich in der Lage, ein funktionierendes triviales Beispiel zu schreiben, aber es fiel auseinander, als ich versuchte, es auf meine realen Objekte anzuwenden, und ich bin mir nicht sicher, warum (das einzige, was ich mir vorstellen kann, ist, dass mein reales Weltobjekte waren Unterklassen anderer Objekte, die ich nicht wirklich kontrollieren kann, und daher gab es einige Inkompatibilitäten mit diesem Ansatz. Das hatte ich:

class Flub(object):
    instances = {}

    def __new__(cls, flubid):
        try:
            self = Flub.instances[flubid]
        except KeyError:
            self = Flub.instances[flubid] = super(Flub, cls).__new__(cls)
            print 'making a new one!'
            self.flubid = flubid
        print id(self)
        return self

    @staticmethod
    def destroy_all():
        for flub in Flub.instances.values():
            print 'killing', flub


a = Flub('foo')
b = Flub('foo')
c = Flub('bar')

print a
print b
print c
print a is b, b is c

Flub.destroy_all()

Welche Ausgabe dies:

making a new one!
139958663753808
139958663753808
making a new one!
139958663753872
<__main__.Flub object at 0x7f4aaa6fb050>
<__main__.Flub object at 0x7f4aaa6fb050>
<__main__.Flub object at 0x7f4aaa6fb090>
True False
killing <__main__.Flub object at 0x7f4aaa6fb050>
killing <__main__.Flub object at 0x7f4aaa6fb090>

Es ist perfekt! Für die beiden angegebenen eindeutigen IDs wurden nur zwei Instanzen erstellt, und in Flub.instances sind eindeutig nur zwei aufgeführt.

Aber als ich versuchte, diesen Ansatz mit den von mir verwendeten Objekten zu verfolgen, bekam ich alle möglichen unsinnigen Fehler, wie__init__() nahm nur 0 Argumente, nicht 2. Also würde ich einige Dinge ändern und dann würde es mir sagen, dass__init__() brauchte ein Argument. Total bizarr.

Nachdem ich eine Weile damit gekämpft hatte, gab ich einfach auf und bewegte alles__new__() schwarze Magie in eine statische Methode namensget, so dass ich anrufen könntePhotograph.get(filename) und es würde nur anrufenPhotograph(filename) wenn der Dateiname noch nicht inPhotograph.instances.

Weiß jemand, wo ich hier falsch gelaufen bin? Gibt es einen besseren Weg, dies zu tun?

Eine andere Art, darüber nachzudenken, ist, dass es einem Singleton ähnlich ist, mit der Ausnahme, dass es sich nicht um ein globales Singleton handelt, sondern nur um Singleton pro Dateiname.

Hier ist mein realer Code mit der staticmethod get wenn du alles zusammen sehen willst.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage