Jak mogę zapamiętać instancję klasy w Pythonie?

OK, oto scenariusz ze świata rzeczywistego: piszę aplikację i mam klasę reprezentującą pewien typ plików (w moim przypadku są to fotografie, ale ten szczegół nie ma znaczenia dla problemu). Każda instancja klasy Photograph powinna być unikalna dla nazwy pliku zdjęcia.

Problem polega na tym, że gdy użytkownik nakazuje mojej aplikacji załadowanie pliku, muszę być w stanie zidentyfikować, kiedy pliki są już załadowane, i użyć istniejącej instancji dla tej nazwy pliku, zamiast tworzyć duplikaty instancji na tej samej nazwie.

Wydaje mi się, że jest to dobra sytuacja do korzystania z zapamiętywania, a jest wiele przykładów tego, ale w tym przypadku nie pamiętam zwykłej funkcji, muszę zapamiętać__init__(). To stwarza problem, ponieważ do tego czasu__init__() zostaje wywołana, jest już za późno, ponieważ została już utworzona nowa instancja.

W moich badaniach znalazłem Pythona__new__() i rzeczywiście byłem w stanie napisać działający trywialny przykład, ale rozpadł się, gdy próbowałem go użyć na moich rzeczywistych obiektach, i nie jestem pewien dlaczego (jedyne, co mogę myśleć, to że mój prawdziwy obiekty świata były podklasami innych obiektów, których tak naprawdę nie mogę kontrolować, więc były pewne niezgodności z tym podejściem). To właśnie miałem:

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()

Które wyjście to:

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>

To jest idealne! Dla dwóch unikatowych identyfikatorów podano tylko dwie instancje, a Flub.instances ma tylko dwie wymienione.

Ale kiedy próbowałem zastosować to podejście z obiektami, z których korzystałem, otrzymałem wszelkiego rodzaju nonsensowne błędy dotyczące tego, jak__init__() wziąłem tylko 0 argumentów, a nie 2. Więc zmieniłbym kilka rzeczy i wtedy to by mi powiedziało__init__() potrzebował argumentu. Całkowicie dziwaczny.

Po chwili walki z nim po prostu zrezygnowałem i przeniosłem wszystko__new__() czarna magia w metodę statyczną o nazwieget, że mógłbym zadzwonićPhotograph.get(filename) i to tylko zadzwoniPhotograph(filename) jeśli nazwa pliku nie jest jeszcze dostępnaPhotograph.instances.

Czy ktoś wie, gdzie poszedłem tutaj źle? Czy jest jakiś lepszy sposób na to?

Innym sposobem myślenia jest to, że jest podobny do singletonu, z wyjątkiem tego, że nie jest globalnie singleton, tylko singleton-per-filename.

Oto mój rzeczywisty kod korzystający z metody staticmethod jeśli chcesz zobaczyć to wszystko razem.

questionAnswers(3)

yourAnswerToTheQuestion