【发布时间】:2012-06-08 09:33:27
【问题描述】:
好的,这是现实世界的场景:我正在编写一个应用程序,并且我有一个代表某种类型文件的类(在我的例子中,这是照片,但该细节与问题无关)。 Photo 类的每个实例对于照片的文件名都应该是唯一的。
问题是,当用户告诉我的应用程序加载文件时,我需要能够识别文件何时已加载,并为该文件名使用现有实例,而不是在同一文件名上创建重复实例。
对我来说,这似乎是一个使用记忆的好情况,并且有很多这样的例子,但在这种情况下,我不只是记忆一个普通的函数,我需要记忆__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>
太完美了!给定的两个唯一 id 只创建了两个实例,而 Flub.instances 显然只列出了两个。
但是当我尝试对我正在使用的对象采用这种方法时,我遇到了各种荒谬的错误,关于 __init__() 如何只接受 0 个参数,而不是 2 个。所以我会改变一些事情然后它会告诉我__init__() 需要一个论点。太奇怪了。
和它打了一阵子,我基本上放弃了,把所有的__new__()黑魔法都移到了一个名为get的静态方法中,这样我就可以调用Photograph.get(filename),它只会调用Photograph(filename) if文件名不在Photograph.instances 中。
有人知道我哪里出错了吗?有没有更好的方法来做到这一点?
另一种思考方式是,它类似于单例,只是它不是全局单例,只是每个文件名的单例。
Here's my real-world code using the staticmethod get 如果你想一起看的话。
【问题讨论】:
-
我已编辑问题以删除您所说的内容。
标签: python caching singleton unique memoization