Ok, ecco lo scenario del mondo reale: sto scrivendo un'applicazione e ho una classe che rappresenta un certo tipo di file (nel mio caso si tratta di fotografie ma quel dettaglio è irrilevante per il problema). Ogni istanza della classe Photograph deve essere unica al nome del file della foto.Come posso memoizzare un'istanza di classe in Python?
Il problema è che quando un utente dice alla mia applicazione di caricare un file, devo essere in grado di identificare quando i file sono già caricati e utilizzare l'istanza esistente per quel nome file, piuttosto che creare istanze duplicate sullo stesso nome file .
Per me sembra una buona situazione usare la memoizzazione, e ci sono molti esempi di questo, ma in questo caso non sto solo memoizzando una funzione ordinaria, ho bisogno di essere memoizing __init__()
. Questo pone un problema, perché quando viene chiamato il numero __init__()
è già troppo tardi perché è già stata creata una nuova istanza.
Nella mia ricerca ho trovato il metodo __new__()
di Python, e in realtà ero in grado di scrivere un esempio banale di lavoro, ma è andato in pezzi quando ho provato ad usarlo sui miei oggetti del mondo reale, e non sono sicuro del perché (l'unica cosa che riesco a pensare è che i miei oggetti del mondo reale erano sottoclassi di altri oggetti che non sono in grado di controllare realmente, e quindi c'erano alcune incompatibilità con questo approccio). Questo è quello che avevo:
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()
quale uscita questo:
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>
E 'perfetto! Sono state fatte solo due istanze per i due ID univoci, e Flub.instances ne ha solo due elencati.
Ma quando ho provato a utilizzare questo approccio con gli oggetti che stavo usando, ho ricevuto tutti i tipi di errori privi di senso su come __init__()
ha preso solo 0 argomenti, non 2. Quindi avrei cambiato alcune cose in giro e poi avrebbe detto me che __init__()
aveva bisogno di un argomento. Totalmente bizzarro.
Dopo un po 'di lotta con esso, ho praticamente appena rinunciato e si è trasferito tutta la magia nera __new__()
in uno staticmethod chiamato get
, in modo tale che potrei chiamare Photograph.get(filename)
e sarebbe chiamare solo Photograph(filename)
se il nome del file non fosse già in Photograph.instances
.
Qualcuno sa dove sono andato storto qui? C'è un modo migliore per farlo?
Un altro modo di pensare a questo proposito è che è simile ad un Singleton, tranne che non è a livello globale Singleton, Singleton solo-per-il nome del file.
Here's my real-world code using the staticmethod get se volete vedere tutto insieme.
Ho modificato la domanda per rimuovere quelle cose che hai detto. – robru