Как мне запомнить экземпляр класса в Python?
Хорошо, вот сценарий реального мира: я пишу приложение, и у меня есть класс, который представляет определенный тип файлов (в моем случае это фотографии, но эта деталь не имеет отношения к проблеме). Каждый экземпляр класса Photograph должен быть уникальным для имени файла фотографии.
Проблема в том, что когда пользователь говорит моему приложению загрузить файл, я должен иметь возможность определить, когда файлы уже загружены, и использовать существующий экземпляр для этого имени файла, а не создавать дубликаты экземпляров с тем же именем файла.
Мне кажется, что это хорошая ситуация, чтобы использовать запоминание, и существует множество примеров этого, но в этом случае я не просто запоминаю обычную функцию, мне нужно запоминать__init__()
, Это создает проблему, потому что к тому времени__init__()
вызывается, это уже слишком поздно, поскольку уже создан новый экземпляр.
В моем исследовании я нашел Python__new__()
метод, и я действительно смог написать рабочий тривиальный пример, но он развалился, когда я попытался использовать его на своих объектах реального мира, и я не уверен почему (единственное, что я могу думать, это то, что мой реальный объекты мира были подклассами других объектов, которые я не могу реально контролировать, и поэтому при таком подходе были некоторые несовместимости). Вот что у меня было:
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()
Какой вывод это:
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>
Это прекрасно! Только два экземпляра были сделаны для двух уникальных идентификаторов, а в Flub.instances явно есть только два перечисленных.
Но когда я попытался использовать этот подход с объектами, которые я использовал, я получил всевозможные бессмысленные ошибки о том, как__init__()
взял только 0 аргументов, а не 2. Так что я бы изменил некоторые вещи, и тогда он сказал бы мне, что__init__()
нужен аргумент. Совершенно странно.
После некоторого времени борьбы с ним, я просто сдался и переместил все__new__()
черная магия в статический метод называетсяget
такой, чтобы я мог позвонитьPhotograph.get(filename)
и это будет только позвонитьPhotograph(filename)
если имя файла не было уже вPhotograph.instances
.
Кто-нибудь знает, где я ошибся здесь? Есть ли лучший способ сделать это?
Другой способ думать об этом состоит в том, что он аналогичен синглтону, за исключением того, что он не глобально синглтон, а только синглтон на имя файла.
Вот мой реальный код с использованием staticmethod get если вы хотите увидеть все это вместе.