Bien, aquí está el escenario del mundo real: estoy escribiendo una aplicación, y tengo una clase que representa un cierto tipo de archivos (en mi caso esto es fotografías, pero ese detalle es irrelevante para el problema). Cada instancia de la clase Fotografía debe ser exclusiva del nombre de archivo de la foto.¿Cómo puedo memorizar una creación de instancias de clase en Python?
El problema es que cuando un usuario le dice a mi aplicación que cargue un archivo, necesito poder identificar cuándo ya están cargados y usar la instancia existente para ese nombre de archivo, en lugar de crear instancias duplicadas en el mismo nombre de archivo .
Para mí, esto parece una buena situación para usar la memoria, y hay muchos ejemplos de eso, pero en este caso no solo estoy recordando una función normal, necesito estar recordando __init__()
. Esto plantea un problema, porque cuando se llama a __init__()
, ya es demasiado tarde ya que ya se creó una nueva instancia.
En mi investigación encontré el método __new__()
de Python, y pude escribir un ejemplo trivial de trabajo, pero se vino abajo cuando traté de usarlo en mis objetos del mundo real, y no estoy seguro de por qué (lo único que se me ocurre es que mis objetos del mundo real eran subclases de otros objetos que realmente no puedo controlar, por lo que hubo algunas incompatibilidades con este enfoque). Esto es lo que tenía:
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()
cual la salida siguiente:
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 perfecto! Solo se crearon dos instancias para los dos identificadores únicos proporcionados, y las instancias Flub claramente solo tienen dos enumeradas.
Pero cuando traté de adoptar este enfoque con los objetos que estaba usando, tengo todo tipo de errores sin sentido acerca de cómo __init__()
tomó sólo 0 argumentos, no 2. Así que cambiaría algunas cosas y entonces se diría yo que __init__()
necesitaba un argumento. Totalmente extraño.
Después de un tiempo de luchar con él, básicamente, sólo di por vencido y se trasladó toda la magia negro __new__()
en una llamada métodoestático get
, de tal manera que yo podría llamar Photograph.get(filename)
y sólo se llamaría Photograph(filename)
si el nombre de archivo no estuviera ya en Photograph.instances
.
¿Alguien sabe dónde me equivoqué aquí? ¿Hay alguna forma mejor de hacer esto?
Otra forma de pensar es que es similar a un singleton, excepto que no es singleton global, solo singleton-por-nombre de archivo.
Here's my real-world code using the staticmethod get si quiere verlo todo junto.
He editado la pregunta para eliminar las cosas que dijiste. – robru