OK, oto scenariusz z prawdziwego świata: piszę aplikację i mam klasę reprezentującą pewien typ plików (w moim przypadku to zdjęcia, ale ten szczegół jest nieistotny dla problemu). Każde wystąpienie klasy Photograph powinno być unikalne dla nazwy pliku zdjęcia.Jak mogę zapamiętać wystąpienie klasy w Pythonie?
Problem polega na tym, że kiedy użytkownik mówi mojej aplikacji, aby załadował plik, muszę być w stanie określić, kiedy pliki są już załadowane i użyć istniejącej instancji dla tej nazwy pliku, zamiast tworzyć zduplikowane wystąpienia na tej samej nazwie pliku .
Wydaje mi się, że to dobra sytuacja, aby użyć funkcji zapamiętywania. Jest wiele takich przykładów, ale w tym przypadku nie pamiętam tylko zwykłej funkcji, muszę zapamiętać numer __init__()
. Stanowi to problem, ponieważ do czasu, gdy zostanie wywołany __init__()
, jest już za późno, ponieważ jest już utworzona nowa instancja.
W moich badań znalazłem __new__()
metody Pythona, a ja rzeczywiście w stanie napisać pracę banalny przykład, ale to rozpadło się, gdy próbowałem go używać na moich przedmiotów rzeczywistych, a nie jestem pewien, dlaczego (jedyne, o czym mogę pomyśleć to to, że moje obiekty z prawdziwego świata były podklasami innych obiektów, których tak naprawdę nie mogę kontrolować, a więc istniały pewne niezgodności z tym podejściem). To co 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>
Jest to idealne rozwiązanie! Zostały wykonane tylko dwa wystąpienia dla dwóch unikalnych identyfikatorów, a Flub.instances ma tylko dwa wymienione.
Ale kiedy próbowałem podejść do tego z obiektami, z których korzystałem, otrzymałem różnego rodzaju bezsensowne błędy dotyczące tego, jak __init__()
zajął tylko 0 argumentów, nie 2. Więc zmieniłbym niektóre rzeczy, a potem powiedziałabym, mnie, że __init__()
potrzebował argumentu. Całkowicie dziwaczne.
Po chwili walki z nim, ja w zasadzie tylko zrezygnował i przeniósł cały __new__()
czarnej magii w staticmethod zwanego get
tak, że mogę zadzwonić Photograph.get(filename)
i to tylko zadzwonić Photograph(filename)
jeśli nazwa pliku nie był już w Photograph.instances
.
Czy ktoś wie, gdzie się tu znalazłem? Czy jest jakiś lepszy sposób na zrobienie tego?
Innym sposobem myślenia jest to, że jest podobny do singletonu, z tym wyjątkiem, że nie jest to pojedynczy singleton, tylko singleton-per-filename.
Here's my real-world code using the staticmethod get jeśli chcesz zobaczyć to wszystko razem.
Zmieniłem to pytanie, aby usunąć te rzeczy, które powiedziałeś. – robru