Como posso memorizar uma instanciação de classe em Python?

Ok, aqui está o cenário do mundo real: estou escrevendo um aplicativo e tenho uma classe que representa um certo tipo de arquivo (no meu caso, são fotografias, mas esse detalhe é irrelevante para o problema). Cada instância da classe Photograph deve ser exclusiva para o nome do arquivo da foto.

O problema é que, quando um usuário informa ao meu aplicativo para carregar um arquivo, eu preciso ser capaz de identificar quando os arquivos já estão carregados e usar a instância existente para esse nome, em vez de criar instâncias duplicadas no mesmo nome de arquivo.

Para mim, isso parece uma boa situação para usar a memoização, e há muitos exemplos disso lá fora, mas neste caso eu não apenas estou memorizando uma função comum, eu preciso estar memoizando__init__(). Isso representa um problema, porque no momento__init__() é chamado já é tarde demais já que há uma nova instância criada.

Na minha pesquisa eu encontrei o Python__new__() método, e eu era realmente capaz de escrever um exemplo trivial de trabalho, mas ele se desfez quando eu tentei usá-lo em meus objetos do mundo real, e eu não sei por que (a única coisa que posso pensar é que o meu real objetos do mundo eram subclasses de outros objetos que eu realmente não posso controlar, então havia algumas incompatibilidades com essa abordagem). Isso é o que eu tive:

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

Qual saída isso:

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>

Está perfeito! Apenas duas instâncias foram feitas para os dois IDs únicos, e o Flub.instances claramente tem apenas dois listados.

Mas quando tentei usar essa abordagem com os objetos que estava usando, recebi todos os tipos de erros absurdos sobre como__init__() levou apenas 0 argumentos, não 2. Então, eu mudaria algumas coisas e então me diria isso__init__() precisava de um argumento. Totalmente bizarro.

Depois de um tempo lutando com isso, eu basicamente desisti e mudei todo o__new__() magia negra em um método estático chamadoget, de tal forma que eu poderia chamarPhotograph.get(filename) e só chamariaPhotograph(filename) se o nome do arquivo já não estavaPhotograph.instances.

Alguém sabe onde eu errei aqui? Existe alguma maneira melhor de fazer isso?

Outra maneira de pensar sobre isso é que é semelhante a um singleton, exceto que não é globalmente singleton, apenas singleton-per-filename.

Aqui está o meu código do mundo real usando o método static get se você quiser ver tudo junto.

questionAnswers(3)

yourAnswerToTheQuestion